aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-05-14 16:41:31 +0000
committerDouglas Gregor <dgregor@apple.com>2009-05-14 16:41:31 +0000
commit501c5ce63c2ff54c103fbab8c1c45234d5a82a57 (patch)
treea223e4e598b2fe41abe14615a95b1b138e3e6ae0 /lib/Sema
parent7633ab80454147ab4892b8de5fd16582a1f221e8 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71773 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/Sema.h30
-rw-r--r--lib/Sema/SemaDecl.cpp47
-rw-r--r--lib/Sema/SemaTemplate.cpp14
3 files changed, 57 insertions, 34 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 5b263b7d92..6cc8a99f8e 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -430,32 +430,10 @@ 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);
- }
+ 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,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a2f7af1d8b..20b24d1231 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3245,6 +3245,51 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T) {
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 @@ 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 (!isAcceptableTagRedeclaration(PrevTagDecl->getTagKind(), Kind)) {
+ if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
bool SafeToContinue
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
Kind != TagDecl::TK_enum);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 7190df107e..1453dcfe5e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -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 (!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 @@ 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 (!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 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc,
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,