| //===------ SemaDeclCXX.cpp - Semantic Analysis for C++ Declarations ------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements semantic analysis for C++ declarations. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Sema.h" |
| #include "clang/Basic/LangOptions.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/Type.h" |
| #include "llvm/ADT/OwningPtr.h" |
| |
| using namespace clang; |
| |
| void |
| Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, |
| ExprTy *defarg) { |
| ParmVarDecl *Param = (ParmVarDecl *)param; |
| llvm::OwningPtr<Expr> DefaultArg((Expr *)defarg); |
| QualType ParamType = Param->getType(); |
| |
| // Default arguments are only permitted in C++ |
| if (!getLangOptions().CPlusPlus) { |
| Diag(EqualLoc, diag::err_param_default_argument, |
| DefaultArg->getSourceRange()); |
| return; |
| } |
| |
| // C++ [dcl.fct.default]p5 |
| // A default argument expression is implicitly converted (clause |
| // 4) to the parameter type. The default argument expression has |
| // the same semantic constraints as the initializer expression in |
| // a declaration of a variable of the parameter type, using the |
| // copy-initialization semantics (8.5). |
| // |
| // FIXME: CheckSingleAssignmentConstraints has the wrong semantics |
| // for C++ (since we want copy-initialization, not copy-assignment), |
| // but we don't have the right semantics implemented yet. Because of |
| // this, our error message is also very poor. |
| QualType DefaultArgType = DefaultArg->getType(); |
| Expr *DefaultArgPtr = DefaultArg.get(); |
| AssignConvertType ConvTy = CheckSingleAssignmentConstraints(ParamType, |
| DefaultArgPtr); |
| if (DefaultArgPtr != DefaultArg.get()) { |
| DefaultArg.take(); |
| DefaultArg.reset(DefaultArgPtr); |
| } |
| if (DiagnoseAssignmentResult(ConvTy, DefaultArg->getLocStart(), |
| ParamType, DefaultArgType, DefaultArg.get(), |
| "in default argument")) { |
| return; |
| } |
| |
| // FIXME: C++ [dcl.fct.default]p3 |
| // A default argument expression shall be specified only in the |
| // parameter-declaration-clause of a function declaration or in a |
| // template-parameter (14.1). It shall not be specified for a |
| // parameter pack. If it is specified in a |
| // parameter-declaration-clause, it shall not occur within a |
| // declarator or abstract-declarator of a parameter-declaration. |
| |
| // Okay: add the default argument to the parameter |
| Param->setDefaultArg(DefaultArg.take()); |
| } |
| |
| // MergeCXXFunctionDecl - Merge two declarations of the same C++ |
| // function, once we already know that they have the same |
| // type. Subroutine of MergeFunctionDecl. |
| FunctionDecl * |
| Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { |
| // C++ [dcl.fct.default]p4: |
| // |
| // For non-template functions, default arguments can be added in |
| // later declarations of a function in the same |
| // scope. Declarations in different scopes have completely |
| // distinct sets of default arguments. That is, declarations in |
| // inner scopes do not acquire default arguments from |
| // declarations in outer scopes, and vice versa. In a given |
| // function declaration, all parameters subsequent to a |
| // parameter with a default argument shall have default |
| // arguments supplied in this or previous declarations. A |
| // default argument shall not be redefined by a later |
| // declaration (not even to the same value). |
| for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { |
| ParmVarDecl *OldParam = Old->getParamDecl(p); |
| ParmVarDecl *NewParam = New->getParamDecl(p); |
| |
| if(OldParam->getDefaultArg() && NewParam->getDefaultArg()) { |
| Diag(NewParam->getLocation(), |
| diag::err_param_default_argument_redefinition, |
| NewParam->getDefaultArg()->getSourceRange()); |
| Diag(OldParam->getLocation(), diag::err_previous_definition); |
| } else if (OldParam->getDefaultArg()) { |
| // Merge the old default argument into the new parameter |
| NewParam->setDefaultArg(OldParam->getDefaultArg()); |
| } |
| } |
| |
| return New; |
| } |
| |
| /// CheckCXXDefaultArguments - Verify that the default arguments for a |
| /// function declaration are well-formed according to C++ |
| /// [dcl.fct.default]. |
| void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { |
| unsigned NumParams = FD->getNumParams(); |
| unsigned p; |
| |
| // Find first parameter with a default argument |
| for (p = 0; p < NumParams; ++p) { |
| ParmVarDecl *Param = FD->getParamDecl(p); |
| if (Param->getDefaultArg()) |
| break; |
| } |
| |
| // C++ [dcl.fct.default]p4: |
| // In a given function declaration, all parameters |
| // subsequent to a parameter with a default argument shall |
| // have default arguments supplied in this or previous |
| // declarations. A default argument shall not be redefined |
| // by a later declaration (not even to the same value). |
| unsigned LastMissingDefaultArg = 0; |
| for(; p < NumParams; ++p) { |
| ParmVarDecl *Param = FD->getParamDecl(p); |
| if (!Param->getDefaultArg()) { |
| if (Param->getIdentifier()) |
| Diag(Param->getLocation(), |
| diag::err_param_default_argument_missing_name, |
| Param->getIdentifier()->getName()); |
| else |
| Diag(Param->getLocation(), |
| diag::err_param_default_argument_missing); |
| |
| LastMissingDefaultArg = p; |
| } |
| } |
| |
| if (LastMissingDefaultArg > 0) { |
| // Some default arguments were missing. Clear out all of the |
| // default arguments up to (and including) the last missing |
| // default argument, so that we leave the function parameters |
| // in a semantically valid state. |
| for (p = 0; p <= LastMissingDefaultArg; ++p) { |
| ParmVarDecl *Param = FD->getParamDecl(p); |
| if (Param->getDefaultArg()) { |
| delete Param->getDefaultArg(); |
| Param->setDefaultArg(0); |
| } |
| } |
| } |
| } |