]> granicus.if.org Git - clang/commitdiff
Fix treatment of types defined in function prototype
authorSerge Pavlov <sepavloff@gmail.com>
Wed, 25 Jun 2014 17:09:41 +0000 (17:09 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Wed, 25 Jun 2014 17:09:41 +0000 (17:09 +0000)
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

lib/AST/Decl.cpp
lib/Sema/SemaDecl.cpp
test/Sema/decl-in-prototype.c
test/SemaCXX/type-definition-in-specifier.cpp

index 7234d4c8327a0fb83174ebac618e810b997d281f..d910a669abf2973be2552043627496cdbe48c99c 100644 (file)
@@ -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);
+      }
+    }
   }
 }
 
index 90499d2749e0713a263d47de4889125f1da20830..073da57b36400c261988acd79b9ca3dfe7ccd02d 100644 (file)
@@ -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);
index 9cb7fabab36c138733ed532d73bc605ee3593a1f..4f581aa54e531dc68e5d6a365dcc1a6e005364c8 100644 (file)
@@ -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'}}
index bda91d93ced322055c4e2a451d904efaa9843874..43443a00e44ba31b1dce561ba895c251f57f2418 100644 (file)
@@ -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'}}
+};