]> granicus.if.org Git - clang/commitdiff
One can use "class" and "struct" interchangeably to refer to a class
authorDouglas Gregor <dgregor@apple.com>
Sun, 3 May 2009 17:18:57 +0000 (17:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 3 May 2009 17:18:57 +0000 (17:18 +0000)
in C++. Fixes <rdar://problem/6815995>.

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

lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/SemaCXX/struct-class-redecl.cpp [new file with mode: 0644]
test/SemaCXX/typedef-redecl.cpp
test/SemaTemplate/class-template-decl.cpp

index e222c9aa3c76b5435dfaced4f5f6590c2b7ab7c5..2bfc6b7857c50fc13b1bd058253b8450a0f9d052 100644 (file)
@@ -429,6 +429,33 @@ public:
   virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, 
                                                 RecordDecl *Record);
 
+  /// \brief Determine whether a tag with a given kind is acceptable
+  /// for a redeclaration of a tag type declared with another tag.
+  ///
+  /// \p T1 and \p T2 are the tag kinds. Since the rules for
+  /// redeclaration of tags are symmetric, it does not matter which is
+  /// the previous declaration and which is the new declaration.
+  bool isAcceptableTagRedeclaration(TagDecl::TagKind T1, TagDecl::TagKind T2) {
+    // C++ [dcl.type.elab]p3:
+    //   The class-key ore num keyword present in the
+    //   elaborated-type-specifier shall agree in kind with the
+    //   declaration to which the name in theelaborated-type-specifier
+    //   refers. This rule also applies to the form of
+    //   elaborated-type-specifier that declares a class-name or
+    //   friend class since it can be construed as referring to the
+    //   definition of the class. Thus, in any
+    //   elaborated-type-specifier, the enum keyword shall be used to
+    //   refer to an enumeration (7.2), the union class-keyshall be
+    //   used to refer to a union (clause 9), and either the class or
+    //   struct class-key shall be used to refer to a class (clause 9)
+    //   declared using the class or struct class-key.
+    if (T1 == T2)
+      return true;
+
+    return (T1 == TagDecl::TK_struct || T1 == TagDecl::TK_class) &&
+           (T2 == TagDecl::TK_struct || T2 == TagDecl::TK_class);
+  }
+
   virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                              SourceLocation KWLoc, const CXXScopeSpec &SS,
                              IdentifierInfo *Name, SourceLocation NameLoc,
index 9647740b14c361202d7bd06b797d2e313fb0cb80..69989b131df649d14b696a0d4e15de154d63af14 100644 (file)
@@ -3295,7 +3295,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
       if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
         // Make sure that this wasn't declared as an enum and now used as a
         // struct or something similar.
-        if (PrevTagDecl->getTagKind() != Kind) {
+        if (!isAcceptableTagRedeclaration(PrevTagDecl->getTagKind(), Kind)) {
           bool SafeToContinue 
             = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
                Kind != TagDecl::TK_enum);
index 43713e11f18c6831872bfae6db57197af146f261..3649abd9a741d583300187801677c278a276622e 100644 (file)
@@ -461,7 +461,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
     //   the class-key shall agree in kind with the original class
     //   template declaration (7.1.5.3).
     RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
-    if (PrevRecordDecl->getTagKind() != Kind) {
+    if (!isAcceptableTagRedeclaration(PrevRecordDecl->getTagKind(), Kind)) {
       Diag(KWLoc, diag::err_use_with_wrong_tag) 
         << Name
         << CodeModificationHint::CreateReplacement(KWLoc, 
@@ -1975,7 +1975,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
   case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
   case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
   }
-  if (ClassTemplate->getTemplatedDecl()->getTagKind() != Kind) {
+  if (!isAcceptableTagRedeclaration(
+                              ClassTemplate->getTemplatedDecl()->getTagKind(),
+                                    Kind)) {
     Diag(KWLoc, diag::err_use_with_wrong_tag) 
       << ClassTemplate
       << CodeModificationHint::CreateReplacement(KWLoc, 
diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp
new file mode 100644 (file)
index 0000000..d6ac366
--- /dev/null
@@ -0,0 +1,8 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class X; // expected-note{{here}}
+typedef struct X * X_t;
+
+template<typename T> class Y;
+template<class U> struct Y { };
+
+union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}
index 10be77cd1a6a892d736291569f3d72b0349e6a6a..e38f47436d1c9dc22478f974f352361ad7f5900b 100644 (file)
@@ -29,5 +29,3 @@ 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 475c7b951923d77365524f078a35d7c54fae7516..c81267771297504ac3117e2badab0503282c12a1 100644 (file)
@@ -14,13 +14,10 @@ extern "C" {
   template<typename T> class D; // expected-error{{templates must have C++ linkage}}
 }
 
-template<class U> class A; // expected-note{{previous template declaration is here}}\
-                           // expected-note{{previous use is here}}
+template<class U> class A; // expected-note{{previous template declaration is here}}
 
 template<int N> class A; // expected-error{{template parameter has a different kind in template redeclaration}}
 
-template<class T> struct A; // expected-error{{use of 'A' with tag type that does not match previous declaration}}
-
 template<int N> class NonTypeTemplateParm;
 
 typedef int INT;