diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 2f281128c710..3839d7f76b29 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -662,6 +662,8 @@ DIAG(err_param_default_argument_references_param, ERROR, "default argument references parameter '%0'") DIAG(err_param_default_argument_references_local, ERROR, "default argument references local variable '%0' of enclosing function") +DIAG(err_param_default_argument_nonfunc, ERROR, + "default arguments can only be specified for parameters in a function declaration") DIAG(err_previous_definition, ERROR, "previous definition is here") DIAG(err_previous_use, ERROR, diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 27eca89ab2bd..e5aab61bb22a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -279,6 +279,7 @@ private: ParmVarDecl *CreateImplicitParameter(Scope *S, IdentifierInfo *Id, SourceLocation IdLoc, QualType Type); void CheckCXXDefaultArguments(FunctionDecl *FD); + void CheckExtraCXXDefaultArguments(Declarator &D); /// More parsing and symbol table subroutines... Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2624f5019db1..9e9509adaa8a 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -785,6 +785,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { assert(!R.isNull() && "GetTypeForDeclarator() returned null type"); if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { + // Check that there are no default arguments (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator); if (!NewTD) return 0; @@ -889,6 +893,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (getLangOptions().CPlusPlus) CheckCXXDefaultArguments(NewFD); } else { + // Check that there are no default arguments (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + if (R.getTypePtr()->isObjCInterfaceType()) { Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object, D.getIdentifier()->getName()); @@ -1108,7 +1116,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { DS.ClearStorageClassSpecs(); } - + // Check that there are no default arguments inside the type of this + // parameter (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + // In this context, we *do not* check D.getInvalidType(). If the declarator // type was invalid, GetTypeForDeclarator() still returns a "valid" type, // though it will not reflect the user specified type. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 827c737ad4ac..c3b6bce447a8 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -134,14 +134,6 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, 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. - // Check that the default argument is well-formed CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this); if (DefaultArgChecker.Visit(DefaultArg.get())) @@ -151,6 +143,34 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, Param->setDefaultArg(DefaultArg.take()); } +/// CheckExtraCXXDefaultArguments - Check for any extra default +/// arguments in the declarator, which is not a function declaration +/// or definition and therefore is not permitted to have default +/// arguments. This routine should be invoked for every declarator +/// that is not a function declaration or definition. +void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { + // 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. + for (unsigned i = 0; i < D.getNumTypeObjects(); ++i) { + DeclaratorChunk &chunk = D.getTypeObject(i); + if (chunk.Kind == DeclaratorChunk::Function) { + for (unsigned argIdx = 0; argIdx < chunk.Fun.NumArgs; ++argIdx) { + ParmVarDecl *Param = (ParmVarDecl *)chunk.Fun.ArgInfo[argIdx].Param; + if (Param->getDefaultArg()) { + Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc, + Param->getDefaultArg()->getSourceRange()); + Param->setDefaultArg(0); + } + } + } + } +} + // MergeCXXFunctionDecl - Merge two declarations of the same C++ // function, once we already know that they have the same // type. Subroutine of MergeFunctionDecl. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 33797c425558..85ff96111a5b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -501,6 +501,10 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { assert(!T.isNull() && "GetTypeForDeclarator() returned null type"); + // Check that there are no default arguments (C++ only). + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + // In this context, we *do not* check D.getInvalidType(). If the declarator // type was invalid, GetTypeForDeclarator() still returns a "valid" type, // though it will not reflect the user specified type. diff --git a/clang/test/Sema/default2.cpp b/clang/test/Sema/default2.cpp index 59489daf7bbe..d3e999c34c6d 100644 --- a/clang/test/Sema/default2.cpp +++ b/clang/test/Sema/default2.cpp @@ -1,7 +1,10 @@ // RUN: clang -fsyntax-only -verify %s void f(int i, int j, int k = 3); +void f(int i, int j, int k); void f(int i, int j = 2, int k); +void f(int i, int j, int k); void f(int i = 1, int j, int k); +void f(int i, int j, int k); void i() { @@ -27,3 +30,9 @@ void h() } void g2(int x, int y, int z = x + y); // expected-error {{default argument references parameter 'x'}} expected-error {{default argument references parameter 'y'}} + +void nondecl(int (*f)(int x = 5)) // {expected-error {{default arguments can only be specified}}} +{ + void (*f2)(int = 17) // {expected-error {{default arguments can only be specified}}} + = (void (*)(int = 42))f; // {expected-error {{default arguments can only be specified}}} +}