From 3cdbbdc53241907939486ba4a9b0c9b5655419c3 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 6 Mar 2013 01:37:38 +0000 Subject: [PATCH] PR15390: If a function returns a pointer to a function, that function type can't have default arguments even though it's a parameter-declaration-clause in a function declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176542 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/DeclSpec.h | 28 ++++++++++++------- lib/Sema/SemaDecl.cpp | 14 ++++------ lib/Sema/SemaDeclCXX.cpp | 13 ++++++++- .../dcl.meaning/dcl.fct.default/p3.cpp | 5 +++- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index d20877b2d3..4f87e9dd75 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -1799,8 +1799,7 @@ public: return DeclTypeInfo[i]; } - void DropFirstTypeObject() - { + void DropFirstTypeObject() { assert(!DeclTypeInfo.empty() && "No type chunks to drop."); DeclTypeInfo.front().destroy(); DeclTypeInfo.erase(DeclTypeInfo.begin()); @@ -1891,17 +1890,13 @@ public: /// isn't a function declarator, if the type specifier refers to a function /// type. This routine checks for both cases. bool isDeclarationOfFunction() const; - - /// \brief Return true if a function declarator at this position would be a - /// function declaration. - bool isFunctionDeclaratorAFunctionDeclaration() const { + + /// \brief Return true if this declaration appears in a context where a + /// function declarator would be a function declaration. + bool isFunctionDeclarationContext() const { if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) return false; - for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I) - if (getTypeObject(I).Kind != DeclaratorChunk::Paren) - return false; - switch (Context) { case FileContext: case MemberContext: @@ -1929,6 +1924,19 @@ public: } llvm_unreachable("unknown context kind!"); } + + /// \brief Return true if a function declarator at this position would be a + /// function declaration. + bool isFunctionDeclaratorAFunctionDeclaration() const { + if (!isFunctionDeclarationContext()) + return false; + + for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I) + if (getTypeObject(I).Kind != DeclaratorChunk::Paren) + return false; + + return true; + } /// takeAttributes - Takes attributes from the given parsed-attributes /// set and add them to this declarator. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5fd775e63a..78f1784ad1 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4117,6 +4117,11 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef) Previous.clear(); + // Check that there are no default arguments other than in the parameters + // of a function declaration (C++ only). + if (getLangOpts().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + NamedDecl *New; bool AddToScope = true; @@ -4356,11 +4361,6 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous.clear(); } - if (getLangOpts().CPlusPlus) { - // Check that there are no default arguments (C++ only). - CheckExtraCXXDefaultArguments(D); - } - DiagnoseFunctionSpecifiers(D); if (D.getDeclSpec().isThreadSpecified()) @@ -4591,10 +4591,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); - // Check that there are no default arguments (C++ only). - if (getLangOpts().CPlusPlus) - CheckExtraCXXDefaultArguments(D); - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); assert(SCSpec != DeclSpec::SCS_typedef && "Parser allowed 'typedef' as storage class VarDecl."); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a2cbe11a34..46010e4bdb 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -352,16 +352,25 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { // 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. + bool MightBeFunction = D.isFunctionDeclarationContext(); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { DeclaratorChunk &chunk = D.getTypeObject(i); if (chunk.Kind == DeclaratorChunk::Function) { + if (MightBeFunction) { + // This is a function declaration. It can have default arguments, but + // keep looking in case its return type is a function type with default + // arguments. + MightBeFunction = false; + continue; + } for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) { ParmVarDecl *Param = cast(chunk.Fun.ArgInfo[argIdx].Param); if (Param->hasUnparsedDefaultArg()) { CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) - << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation()); + << SourceRange((*Toks)[1].getLocation(), + Toks->back().getLocation()); delete Toks; chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0; } else if (Param->getDefaultArg()) { @@ -370,6 +379,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { Param->setDefaultArg(0); } } + } else if (chunk.Kind != DeclaratorChunk::Paren) { + MightBeFunction = false; } } } diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp index 5467a9222c..e03c2164ba 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only be specified}} { @@ -8,6 +8,9 @@ void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only struct X0 { int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}} + void (*g())(int = 22); // expected-error{{default arguments can only be specified for parameters in a function declaration}} + void (*h(int = 49))(int); + auto i(int) -> void (*)(int = 9); // expected-error{{default arguments can only be specified for parameters in a function declaration}} void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}} }; -- 2.40.0