r211718 - Fix treatment of types defined in function prototype

Serge Pavlov sepavloff at gmail.com
Wed Jun 25 10:09:42 PDT 2014


Author: sepavloff
Date: Wed Jun 25 12:09:41 2014
New Revision: 211718

URL: http://llvm.org/viewvc/llvm-project?rev=211718&view=rev
Log:
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

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

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=211718&r1=211717&r2=211718&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Jun 25 12:09:41 2014
@@ -2544,6 +2544,18 @@ void FunctionDecl::setDeclsInPrototypeSc
     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);
+      }
+    }
   }
 }
 

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=211718&r1=211717&r2=211718&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jun 25 12:09:41 2014
@@ -10874,11 +10874,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned
       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);

Modified: cfe/trunk/test/Sema/decl-in-prototype.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/decl-in-prototype.c?rev=211718&r1=211717&r2=211718&view=diff
==============================================================================
--- cfe/trunk/test/Sema/decl-in-prototype.c (original)
+++ cfe/trunk/test/Sema/decl-in-prototype.c Wed Jun 25 12:09:41 2014
@@ -31,3 +31,7 @@ void f6(struct z {int b;} c) { // expect
     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'}}

Modified: cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp?rev=211718&r1=211717&r2=211718&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp (original)
+++ cfe/trunk/test/SemaCXX/type-definition-in-specifier.cpp Wed Jun 25 12:09:41 2014
@@ -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'}}
+};





More information about the cfe-commits mailing list