From a826147eef05d1d4fa0f3efdd1eeb4c71ae13b9d Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Wed, 25 Jun 2014 17:09:41 +0000 Subject: [PATCH] Fix treatment of types defined in function prototype Types defined in function prototype are diagnosed earlier in C++ compilation. They are put into declaration context where the prototype is introduced. Later on, when FunctionDecl object is created, these types are moved into the function context. This patch fixes PR19018 and PR18963. Differential Revision: http://reviews.llvm.org/D4145 llvm-svn: 211718 --- clang/lib/AST/Decl.cpp | 12 +++++++ clang/lib/Sema/SemaDecl.cpp | 33 +++++++++-------- clang/test/Sema/decl-in-prototype.c | 4 +++ .../test/SemaCXX/type-definition-in-specifier.cpp | 41 ++++++++++++++++++++++ 4 files changed, 76 insertions(+), 14 deletions(-) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 7234d4c..d910a66 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2544,6 +2544,18 @@ void FunctionDecl::setDeclsInPrototypeScope(ArrayRef NewDecls) { NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()]; std::copy(NewDecls.begin(), NewDecls.end(), A); DeclsInPrototypeScope = ArrayRef(A, NewDecls.size()); + // Move declarations introduced in prototype to the function context. + for (auto I : NewDecls) { + DeclContext *DC = I->getDeclContext(); + // Forward-declared reference to an enumeration is not added to + // declaration scope, so skip declaration that is absent from its + // declaration contexts. + if (DC->containsDecl(I)) { + DC->removeDecl(I); + I->setDeclContext(this); + addDecl(I); + } + } } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 90499d2..073da57 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10874,11 +10874,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, while (isa(SearchDC) || isa(SearchDC)) SearchDC = SearchDC->getParent(); } - } else if (S->isFunctionPrototypeScope()) { - // If this is an enum declaration in function prototype scope, set its - // initial context to the translation unit. - // FIXME: [citation needed] - SearchDC = Context.getTranslationUnitDecl(); } if (Previous.isSingleResult() && @@ -11351,27 +11346,37 @@ CreateNewDecl: else if (!SearchDC->isFunctionOrMethod()) New->setModulePrivate(); } - + // If this is a specialization of a member class (of a class template), // check the specialization. if (isExplicitSpecialization && CheckMemberSpecialization(New, Previous)) Invalid = true; - - if (Invalid) - New->setInvalidDecl(); - - if (Attr) - ProcessDeclAttributeList(S, New, Attr); // If we're declaring or defining a tag in function prototype scope in C, // note that this type can only be used within the function and add it to // the list of decls to inject into the function definition scope. - if (!getLangOpts().CPlusPlus && (Name || Kind == TTK_Enum) && + if ((Name || Kind == TTK_Enum) && getNonFieldDeclScope(S)->isFunctionPrototypeScope()) { - Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); + if (getLangOpts().CPlusPlus) { + // C++ [dcl.fct]p6: + // Types shall not be defined in return or parameter types. + if (TUK == TUK_Definition && !IsTypeSpecifier) { + Diag(Loc, diag::err_type_defined_in_param_type) + << Name; + Invalid = true; + } + } else { + Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); + } DeclsInPrototypeScope.push_back(New); } + if (Invalid) + New->setInvalidDecl(); + + if (Attr) + ProcessDeclAttributeList(S, New, Attr); + // Set the lexical context. If the tag has a C++ scope specifier, the // lexical context will be different from the semantic context. New->setLexicalDeclContext(CurContext); diff --git a/clang/test/Sema/decl-in-prototype.c b/clang/test/Sema/decl-in-prototype.c index 9cb7fab..4f581aa 100644 --- a/clang/test/Sema/decl-in-prototype.c +++ b/clang/test/Sema/decl-in-prototype.c @@ -31,3 +31,7 @@ void f6(struct z {int b;} c) { // expected-warning {{declaration of 'struct z' w struct z d; d.b = 4; } + +void pr19018_1 (enum e19018 { qq } x); // expected-warning{{declaration of 'enum e19018' will not be visible outside of this function}} +enum e19018 qq; //expected-error{{tentative definition has type 'enum e19018' that is never completed}} \ + //expected-note{{forward declaration of 'enum e19018'}} diff --git a/clang/test/SemaCXX/type-definition-in-specifier.cpp b/clang/test/SemaCXX/type-definition-in-specifier.cpp index bda91d9..43443a0 100644 --- a/clang/test/SemaCXX/type-definition-in-specifier.cpp +++ b/clang/test/SemaCXX/type-definition-in-specifier.cpp @@ -23,3 +23,44 @@ void f0() { struct S5 { int x; } f1() { return S5(); } // expected-error{{result type}} void f2(struct S6 { int x; } p); // expected-error{{parameter type}} + +struct pr19018 { + short foo6 (enum bar0 {qq} bar3); // expected-error{{cannot be defined in a parameter type}} +}; + +void pr19018_1 (enum e19018_1 {qq} x); // expected-error{{cannot be defined in a parameter type}} +void pr19018_1a (enum e19018_1 {qq} x); // expected-error{{cannot be defined in a parameter type}} +e19018_1 x2; // expected-error{{unknown type name 'e19018_1'}} + +void pr19018_2 (enum {qq} x); // expected-error{{cannot be defined in a parameter type}} +void pr19018_3 (struct s19018_2 {int qq;} x); // expected-error{{cannot be defined in a parameter type}} +void pr19018_4 (struct {int qq;} x); // expected-error{{cannot be defined in a parameter type}} +void pr19018_5 (struct { void qq(); } x); // expected-error{{cannot be defined in a parameter type}} +void pr19018_5 (struct s19018_2 { void qq(); } x); // expected-error{{cannot be defined in a parameter type}} + +struct pr19018a { + static int xx; + void func1(enum t19018 {qq} x); // expected-error{{cannot be defined in a parameter type}} + void func2(enum t19018 {qq} x); // expected-error{{cannot be defined in a parameter type}} + void func3(enum {qq} x); // expected-error{{cannot be defined in a parameter type}} + void func4(struct t19018 {int qq;} x); // expected-error{{cannot be defined in a parameter type}} + void func5(struct {int qq;} x); // expected-error{{cannot be defined in a parameter type}} + void func6(struct { void qq(); } x); // expected-error{{cannot be defined in a parameter type}} + void func7(struct t19018 { void qq(); } x); // expected-error{{cannot be defined in a parameter type}} + void func8(struct { int qq() { return xx; }; } x); // expected-error{{cannot be defined in a parameter type}} + void func9(struct t19018 { int qq() { return xx; }; } x); // expected-error{{cannot be defined in a parameter type}} +}; + +struct s19018b { + void func1 (enum en_2 {qq} x); // expected-error{{cannot be defined in a parameter type}} + en_2 x1; // expected-error{{unknown type name 'en_2'}} + void func2 (enum en_3 {qq} x); // expected-error{{cannot be defined in a parameter type}} + enum en_3 x2; // expected-error{{ISO C++ forbids forward references to 'enum' types}} \ + // expected-error{{field has incomplete type 'enum en_3'}} \ + // expected-note{{forward declaration of 'en_3'}} +}; + +struct pr18963 { + short bar5 (struct foo4 {} bar2); // expected-error{{'foo4' cannot be defined in a parameter type}} + long foo5 (float foo6 = foo4); // expected-error{{use of undeclared identifier 'foo4'}} +}; -- 2.7.4