forked from OSchip/llvm-project
One can use "class" and "struct" interchangeably to refer to a class
in C++. Fixes <rdar://problem/6815995>. llvm-svn: 70784
This commit is contained in:
parent
4c78596182
commit
f9aa5260a9
|
@ -429,6 +429,33 @@ public:
|
||||||
virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
virtual DeclPtrTy BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
|
||||||
RecordDecl *Record);
|
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,
|
virtual DeclPtrTy ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
SourceLocation KWLoc, const CXXScopeSpec &SS,
|
SourceLocation KWLoc, const CXXScopeSpec &SS,
|
||||||
IdentifierInfo *Name, SourceLocation NameLoc,
|
IdentifierInfo *Name, SourceLocation NameLoc,
|
||||||
|
|
|
@ -3295,7 +3295,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
|
if (TK == TK_Reference || isDeclInScope(PrevDecl, SearchDC, S)) {
|
||||||
// Make sure that this wasn't declared as an enum and now used as a
|
// Make sure that this wasn't declared as an enum and now used as a
|
||||||
// struct or something similar.
|
// struct or something similar.
|
||||||
if (PrevTagDecl->getTagKind() != Kind) {
|
if (!isAcceptableTagRedeclaration(PrevTagDecl->getTagKind(), Kind)) {
|
||||||
bool SafeToContinue
|
bool SafeToContinue
|
||||||
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
|
= (PrevTagDecl->getTagKind() != TagDecl::TK_enum &&
|
||||||
Kind != 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
|
// the class-key shall agree in kind with the original class
|
||||||
// template declaration (7.1.5.3).
|
// template declaration (7.1.5.3).
|
||||||
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
|
RecordDecl *PrevRecordDecl = PrevClassTemplate->getTemplatedDecl();
|
||||||
if (PrevRecordDecl->getTagKind() != Kind) {
|
if (!isAcceptableTagRedeclaration(PrevRecordDecl->getTagKind(), Kind)) {
|
||||||
Diag(KWLoc, diag::err_use_with_wrong_tag)
|
Diag(KWLoc, diag::err_use_with_wrong_tag)
|
||||||
<< Name
|
<< Name
|
||||||
<< CodeModificationHint::CreateReplacement(KWLoc,
|
<< 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_union: Kind = TagDecl::TK_union; break;
|
||||||
case DeclSpec::TST_class: Kind = TagDecl::TK_class; 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)
|
Diag(KWLoc, diag::err_use_with_wrong_tag)
|
||||||
<< ClassTemplate
|
<< ClassTemplate
|
||||||
<< CodeModificationHint::CreateReplacement(KWLoc,
|
<< CodeModificationHint::CreateReplacement(KWLoc,
|
||||||
|
|
|
@ -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}}
|
|
@ -29,5 +29,3 @@ typedef I I;
|
||||||
|
|
||||||
struct s { };
|
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}}
|
|
||||||
|
|
|
@ -14,13 +14,10 @@ extern "C" {
|
||||||
template<typename T> class D; // expected-error{{templates must have C++ linkage}}
|
template<typename T> class D; // expected-error{{templates must have C++ linkage}}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U> class A; // expected-note{{previous template declaration is here}}\
|
template<class U> class A; // expected-note{{previous template declaration is here}}
|
||||||
// expected-note{{previous use is here}}
|
|
||||||
|
|
||||||
template<int N> class A; // expected-error{{template parameter has a different kind in template redeclaration}}
|
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;
|
template<int N> class NonTypeTemplateParm;
|
||||||
|
|
||||||
typedef int INT;
|
typedef int INT;
|
||||||
|
|
Loading…
Reference in New Issue