summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2014-06-25 17:09:41 +0000
committerSerge Pavlov <sepavloff@gmail.com>2014-06-25 17:09:41 +0000
commit525f68c5da062214c9bca4d85b9febf8d8ebef5b (patch)
tree7fc0531c1115848f1c980bd2a7773df895e2a921
parentee276c176ee1e682a793c8b6da4ca5895622ac00 (diff)
downloadclang-525f68c5da062214c9bca4d85b9febf8d8ebef5b.tar.gz
clang-525f68c5da062214c9bca4d85b9febf8d8ebef5b.tar.bz2
clang-525f68c5da062214c9bca4d85b9febf8d8ebef5b.tar.xz
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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211718 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/Decl.cpp12
-rw-r--r--lib/Sema/SemaDecl.cpp33
-rw-r--r--test/Sema/decl-in-prototype.c4
-rw-r--r--test/SemaCXX/type-definition-in-specifier.cpp41
4 files changed, 76 insertions, 14 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7234d4c832..d910a669ab 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -2544,6 +2544,18 @@ void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
DeclsInPrototypeScope = ArrayRef<NamedDecl *>(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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 90499d2749..073da57b36 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -10874,11 +10874,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(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/test/Sema/decl-in-prototype.c b/test/Sema/decl-in-prototype.c
index 9cb7fabab3..4f581aa54e 100644
--- a/test/Sema/decl-in-prototype.c
+++ b/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/test/SemaCXX/type-definition-in-specifier.cpp b/test/SemaCXX/type-definition-in-specifier.cpp
index bda91d93ce..43443a00e4 100644
--- a/test/SemaCXX/type-definition-in-specifier.cpp
+++ b/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'}}
+};