forked from OSchip/llvm-project
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. llvm-svn: 71773
This commit is contained in:
parent
8533490df9
commit
d9034f0b89
|
@ -86,6 +86,8 @@ def InvalidOffsetof : DiagGroup<"invalid-offsetof">;
|
|||
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 @@ def Most : DiagGroup<"most", [
|
|||
Comment,
|
||||
Format,
|
||||
Implicit,
|
||||
MismatchedTags,
|
||||
MultiChar,
|
||||
Switch,
|
||||
Trigraphs,
|
||||
|
|
|
@ -812,6 +812,10 @@ def err_conflicting_types : Error<"conflicting types for %0">;
|
|||
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<
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue