[cfe-commits] r71773 - in /cfe/trunk: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/SemaCXX/struct-class-redecl.cpp

Douglas Gregor dgregor at apple.com
Thu May 14 09:41:43 PDT 2009


Author: dgregor
Date: Thu May 14 11:41:31 2009
New Revision: 71773

URL: http://llvm.org/viewvc/llvm-project?rev=71773&view=rev
Log:
In C++, warn when something previously declared as a "struct" is later
declared as a "class", or vice-versa. This warning is under the
control of -Wmismatched-tags, which is off by default.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaCXX/struct-class-redecl.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Thu May 14 11:41:31 2009
@@ -86,6 +86,8 @@
 def : DiagGroup<"strict-prototypes">;
 def : DiagGroup<"strict-selector-match">;
 def Switch         : DiagGroup<"switch">;
+def MismatchedTags    : DiagGroup<"mismatched-tags">;
+
 def : DiagGroup<"type-limits">;
 def Uninitialized  : DiagGroup<"uninitialized">;
 def UnknownPragmas : DiagGroup<"unknown-pragmas">;
@@ -107,6 +109,7 @@
     Comment,
     Format,
     Implicit,
+    MismatchedTags,
     MultiChar,
     Switch,
     Trigraphs,

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu May 14 11:41:31 2009
@@ -812,6 +812,10 @@
 def err_nested_redefinition : Error<"nested redefinition of %0">;
 def err_use_with_wrong_tag : Error<
   "use of %0 with tag type that does not match previous declaration">;
+def warn_struct_class_tag_mismatch : Warning<
+    "%select{struct|class}0 %select{|template}1 %2 was previously declared "
+    "as a %select{struct|class}3 %select{|template}1">,
+    InGroup<MismatchedTags>, DefaultIgnore;
 def ext_forward_ref_enum : Extension<
   "ISO C forbids forward references to 'enum' types">;
 def err_forward_ref_enum : Error<

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu May 14 11:41:31 2009
@@ -430,32 +430,10 @@
   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);
-  }
+  bool isAcceptableTagRedeclaration(const TagDecl *Previous, 
+                                    TagDecl::TagKind NewTag,
+                                    SourceLocation NewTagLoc,
+                                    const IdentifierInfo &Name);
 
   virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
                              SourceLocation KWLoc, const CXXScopeSpec &SS,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu May 14 11:41:31 2009
@@ -3245,6 +3245,51 @@
   return NewTD;
 }
 
+
+/// \brief Determine whether a tag with a given kind is acceptable
+/// as a redeclaration of the given tag declaration.
+///
+/// \returns true if the new tag kind is acceptable, false otherwise.
+bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, 
+                                        TagDecl::TagKind NewTag,
+                                        SourceLocation NewTagLoc,
+                                        const IdentifierInfo &Name) {
+  // C++ [dcl.type.elab]p3:
+  //   The class-key or enum 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.
+  TagDecl::TagKind OldTag = Previous->getTagKind();
+  if (OldTag == NewTag)
+    return true;
+ 
+  if ((OldTag == TagDecl::TK_struct || OldTag == TagDecl::TK_class) &&
+      (NewTag == TagDecl::TK_struct || NewTag == TagDecl::TK_class)) {
+    // Warn about the struct/class tag mismatch.
+    bool isTemplate = false;
+    if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
+      isTemplate = Record->getDescribedClassTemplate();
+
+    Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
+      << (NewTag == TagDecl::TK_class)
+      << isTemplate << &Name
+      << (OldTag == TagDecl::TK_class)
+      << CodeModificationHint::CreateReplacement(SourceRange(NewTagLoc),
+                              OldTag == TagDecl::TK_class? "class" : "struct");
+    Diag(Previous->getLocation(), diag::note_previous_use);
+    return true;
+  }
+  return false;
+}
+
 /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'.  In the
 /// former case, Name will be non-null.  In the later case, Name will be null.
 /// TagSpec indicates what kind of tag this is. TK indicates whether this is a
@@ -3347,7 +3392,7 @@
       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 (!isAcceptableTagRedeclaration(PrevTagDecl->getTagKind(), Kind)) {
+        if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
           bool SafeToContinue 
             = (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
                Kind != TagDecl::TK_enum);

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 14 11:41:31 2009
@@ -461,7 +461,7 @@
     //   the class-key shall agree in kind with the original class
     //   template declaration (7.1.5.3).
     RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
-    if (!isAcceptableTagRedeclaration(PrevRecordDecl->getTagKind(), Kind)) {
+    if (!isAcceptableTagRedeclaration(PrevRecordDecl, Kind, KWLoc, *Name)) {
       Diag(KWLoc, diag::err_use_with_wrong_tag) 
         << Name
         << CodeModificationHint::CreateReplacement(KWLoc, 
@@ -2026,9 +2026,9 @@
   case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
   case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
   }
-  if (!isAcceptableTagRedeclaration(
-                              ClassTemplate->getTemplatedDecl()->getTagKind(),
-                                    Kind)) {
+  if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
+                                    Kind, KWLoc, 
+                                    *ClassTemplate->getIdentifier())) {
     Diag(KWLoc, diag::err_use_with_wrong_tag) 
       << ClassTemplate
       << CodeModificationHint::CreateReplacement(KWLoc, 
@@ -2182,9 +2182,9 @@
   case DeclSpec::TST_union:  Kind = TagDecl::TK_union; break;
   case DeclSpec::TST_class:  Kind = TagDecl::TK_class; break;
   }
-  if (!isAcceptableTagRedeclaration(
-                              ClassTemplate->getTemplatedDecl()->getTagKind(),
-                                    Kind)) {
+  if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
+                                    Kind, KWLoc, 
+                                    *ClassTemplate->getIdentifier())) {
     Diag(KWLoc, diag::err_use_with_wrong_tag) 
       << ClassTemplate
       << CodeModificationHint::CreateReplacement(KWLoc, 

Modified: cfe/trunk/test/SemaCXX/struct-class-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/struct-class-redecl.cpp?rev=71773&r1=71772&r2=71773&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/struct-class-redecl.cpp (original)
+++ cfe/trunk/test/SemaCXX/struct-class-redecl.cpp Thu May 14 11:41:31 2009
@@ -1,8 +1,8 @@
-// RUN: clang-cc -fsyntax-only -verify %s
-class X; // expected-note{{here}}
-typedef struct X * X_t;
+// RUN: clang-cc -fsyntax-only -Wmismatched-tags -verify %s
+class X; // expected-note 2{{here}}
+typedef struct X * X_t; // expected-warning{{previously declared}}
 
-template<typename T> class Y;
-template<class U> struct Y { };
+template<typename T> struct Y; // expected-note{{previous}}
+template<class U> class Y { }; // expected-warning{{previously declared}}
 
 union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}}





More information about the cfe-commits mailing list