From: Chris Lattner Date: Tue, 8 Apr 2008 05:04:30 +0000 (+0000) Subject: Add support for C++ default arguments, and rework Parse-Sema X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3d1cee369820dba83d7fccc605b91e838cf412b4;p=clang Add support for C++ default arguments, and rework Parse-Sema interaction for function parameters, fixing PR2046. Patch by Doug Gregor! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49370 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp new file mode 100644 index 0000000000..e7bf7bff4b --- /dev/null +++ b/lib/Sema/SemaDeclCXX.cpp @@ -0,0 +1,158 @@ +//===------ 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 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); + } + } + } +}