]> granicus.if.org Git - clang/commitdiff
Complete semantic checking for typedef redeclarations in C++. The
authorDouglas Gregor <dgregor@apple.com>
Wed, 28 Jan 2009 17:15:10 +0000 (17:15 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 28 Jan 2009 17:15:10 +0000 (17:15 +0000)
rules are slightly different than in C, and now we handle both
dialects properly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63211 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.def
lib/Sema/SemaDecl.cpp
test/SemaCXX/class.cpp
test/SemaCXX/typedef-redecl.cpp
www/cxx_status.html

index f73f6ee23fb49753bba305df1f0a864f13e5bdd1..6cc23dd427a5dd43b64306fd87f49c728cd6a4cf 100644 (file)
@@ -468,6 +468,8 @@ DIAG(err_redefinition_different_kind, ERROR,
      "redefinition of %0 as different kind of symbol")
 DIAG(err_redefinition_different_typedef, ERROR,
      "typedef redefinition with different types (%0 vs %1)")
+DIAG(err_tag_definition_of_typedef, ERROR,
+     "definition of type %0 conflicts with typedef of the same name")
 DIAG(err_conflicting_types, ERROR,
      "conflicting types for %0")
 DIAG(err_nested_redefinition, ERROR,
index e0cb526c6012ce304595886e21310dc8c576c4fa..22650f525dbb8a615d07e15a2f02a01f3c0bf9f0 100644 (file)
@@ -384,23 +384,31 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
     }
     // Fall through - the typedef name was not a builtin type.
   }
-  // Verify the old decl was also a typedef.
-  TypedefDecl *Old = dyn_cast<TypedefDecl>(OldD);
+  // Verify the old decl was also a type.
+  TypeDecl *Old = dyn_cast<TypeDecl>(OldD);
   if (!Old) {
-    Diag(New->getLocation(), diag::err_redefinition_different_kind)
+    Diag(New->getLocation(), diag::err_redefinition_different_kind) 
       << New->getDeclName();
     if (!objc_types)
       Diag(OldD->getLocation(), diag::note_previous_definition);
     return New;
   }
-  
+
+  // Determine the "old" type we'll use for checking and diagnostics.  
+  QualType OldType;
+  if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old))
+    OldType = OldTypedef->getUnderlyingType();
+  else
+    OldType = Context.getTypeDeclType(Old);
+
   // If the typedef types are not identical, reject them in all languages and
   // with any extensions enabled.
-  if (Old->getUnderlyingType() != New->getUnderlyingType() && 
-      Context.getCanonicalType(Old->getUnderlyingType()) != 
+
+  if (OldType != New->getUnderlyingType() && 
+      Context.getCanonicalType(OldType) != 
       Context.getCanonicalType(New->getUnderlyingType())) {
     Diag(New->getLocation(), diag::err_redefinition_different_typedef)
-      << New->getUnderlyingType() << Old->getUnderlyingType();
+      << New->getUnderlyingType() << OldType;
     if (!objc_types)
       Diag(Old->getLocation(), diag::note_previous_definition);
     return New;
@@ -1276,8 +1284,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl,
 
   // In C++, the previous declaration we find might be a tag type
   // (class or enum). In this case, the new declaration will hide the
-  // tag type. 
-  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+  // tag type. Note that this does does not apply if we're declaring a
+  // typedef (C++ [dcl.typedef]p4).
+  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag &&
+      D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
     PrevDecl = 0;
 
   QualType R = GetTypeForDeclarator(D, S);
@@ -2887,8 +2897,6 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
   }
 
   if (PrevDecl) {    
-    assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
-            "unexpected Decl type");
     if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
       // If this is a use of a previous tag, or if the tag is already declared
       // in the same scope (so that the definition/declaration completes or
@@ -2955,7 +2963,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
       // is non-NULL, it's a definition of the tag declared by
       // PrevDecl. If it's NULL, we have a new definition.
     } else {
-      // PrevDecl is a namespace.
+      // PrevDecl is a namespace, template, or anything else
+      // that lives in the IDNS_Tag identifier namespace.
       if (isDeclInScope(PrevDecl, SearchDC, S)) {
         // The tag name clashes with a namespace name, issue an error and
         // recover by making this tag be anonymous.
@@ -3054,6 +3063,30 @@ CreateNewDecl:
       New->addAttr(new PackedAttr(Alignment * 8));
   }
 
+  if (getLangOptions().CPlusPlus && SS.isEmpty() && Name && !Invalid) {
+    // C++ [dcl.typedef]p3:
+    //   [...] Similarly, in a given scope, a class or enumeration
+    //   shall not be declared with the same name as a typedef-name
+    //   that is declared in that scope and refers to a type other
+    //   than the class or enumeration itself.
+    LookupResult Lookup = LookupName(S, Name, 
+                                     LookupCriteria(LookupCriteria::Ordinary, 
+                                                    true, true));
+    TypedefDecl *PrevTypedef = 0;
+    if (Lookup.getKind() == LookupResult::Found)
+      PrevTypedef = dyn_cast<TypedefDecl>(Lookup.getAsDecl());
+
+    if (PrevTypedef && isDeclInScope(PrevTypedef, SearchDC, S) &&
+        Context.getCanonicalType(Context.getTypeDeclType(PrevTypedef)) !=
+          Context.getCanonicalType(Context.getTypeDeclType(New))) {
+      Diag(Loc, diag::err_tag_definition_of_typedef)
+        << Context.getTypeDeclType(New)
+        << PrevTypedef->getUnderlyingType();
+      Diag(PrevTypedef->getLocation(), diag::note_previous_definition);
+      Invalid = true;
+    }
+  }
+
   if (Invalid)
     New->setInvalidDecl();
 
index d739af87dd79b42d7f8688c2b9ff0f58f18c5152..02608faa0f641d5de445397c9bc3f35756d2b5ec 100644 (file)
@@ -30,7 +30,7 @@ public:
   func btm : 1; // expected-error {{error: bit-field 'btm' with non-integral type}}
   NestedC bc : 1; // expected-error {{error: bit-field 'bc' with non-integral type}}
 
-  enum E { en1, en2 };
+  enum E1 { en1, en2 };
 
   int i = 0; // expected-error {{error: 'i' can only be initialized if it is a static const integral data member}}
   static int si = 0; // expected-error {{error: 'si' can only be initialized if it is a static const integral data member}}
index eabcef8b3198fe164ddd3c86dbf7544d022c8072..016882feb2bef4559de3b4f0b5f83c625d7450f7 100644 (file)
@@ -1,12 +1,33 @@
 // RUN: clang -fsyntax-only -verify %s 
-
 typedef int INT;
 typedef INT REALLY_INT; // expected-note {{previous definition is here}}
 typedef REALLY_INT REALLY_REALLY_INT;
 typedef REALLY_INT BOB;
 typedef float REALLY_INT; // expected-error{{typedef redefinition with different types ('float' vs 'INT')}}
 
-class X {
+struct X {
   typedef int result_type; // expected-note {{previous definition is here}}
   typedef INT result_type; // expected-error {{redefinition of 'result_type'}}
 };
+
+struct Y; // expected-note{{previous definition is here}}
+typedef int Y;  // expected-error{{typedef redefinition with different types ('int' vs 'struct Y')}}
+
+typedef int Y2; // expected-note{{previous definition is here}}
+struct Y2; // expected-error{{definition of type 'struct Y2' conflicts with typedef of the same name}}
+
+void f(); // expected-note{{previous definition is here}}
+typedef int f; // expected-error{{redefinition of 'f' as different kind of symbol}}
+
+typedef int f2; // expected-note{{previous definition is here}}
+void f2(); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+
+typedef struct s s; 
+typedef int I; 
+typedef int I; 
+typedef I I; 
+
+struct s { };
+
+typedef class st { /* ... */ } st; // expected-note{{previous use is here}}
+struct st; // expected-error{{use of 'st' with tag type that does not match previous declaration}}
index a83157b193e23e14705818aadaebdc6570dcc112..22a419af5eeaa7b84ca2944aa5ed18f48dd779a5 100644 (file)
@@ -944,13 +944,20 @@ welcome!</p>
   <td class="complete" align="center">&#x2713;</td>\r
   <td class="complete" align="center">&#x2713;</td>\r
   <td></td>\r
-  <td>I think we handle everything.</td>\r
+  <td></td>\r
 </tr>\r
 <tr><td>7 [dcl.dcl]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
 <tr><td>&nbsp;&nbsp;7.1 [dcl.spec]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
 <tr><td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.1 [dcl.stc]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
 <tr><td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.2 [dcl.fct.spec]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
-<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.3 [dcl.typedef]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
+<tr>\r
+  <td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.3 [dcl.typedef]</td>\r
+  <td class="complete" align="center">&#x2713;</td>\r
+  <td class="complete" align="center">&#x2713;</td>\r
+  <td class="complete" align="center">&#x2713;</td>\r
+  <td class="advanced"></td>\r
+  <td>Typedefs of anonymous tag types do not use the name of the typedef for linkage purposes.</td>\r
+</tr>\r
 <tr><td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.4 [dcl.friend]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
 <tr><td>&nbsp;&nbsp;&nbsp;&nbsp;7.1.5 [dcl.type]</td><td></td><td></td><td></td><td></td><td></td></tr>\r
 <tr><td>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7.1.5.1 [dcl.type.cv]</td><td></td><td></td><td></td><td></td><td></td></tr>\r