From f9aa5260a97b1e9b9f6e65a0c6a0c4d1e51996e0 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 3 May 2009 17:18:57 +0000 Subject: [PATCH] One can use "class" and "struct" interchangeably to refer to a class in C++. Fixes . llvm-svn: 70784 --- clang/lib/Sema/Sema.h | 27 +++++++++++++++++++ clang/lib/Sema/SemaDecl.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 6 +++-- clang/test/SemaCXX/struct-class-redecl.cpp | 8 ++++++ clang/test/SemaCXX/typedef-redecl.cpp | 2 -- .../test/SemaTemplate/class-template-decl.cpp | 5 +--- 6 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 clang/test/SemaCXX/struct-class-redecl.cpp diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index e222c9aa3c76..2bfc6b7857c5 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9647740b14c3..69989b131df6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 43713e11f18c..3649abd9a741 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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 (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/clang/test/SemaCXX/struct-class-redecl.cpp b/clang/test/SemaCXX/struct-class-redecl.cpp new file mode 100644 index 000000000000..d6ac3661a39a --- /dev/null +++ b/clang/test/SemaCXX/struct-class-redecl.cpp @@ -0,0 +1,8 @@ +// RUN: clang-cc -fsyntax-only -verify %s +class X; // expected-note{{here}} +typedef struct X * X_t; + +template class Y; +template struct Y { }; + +union X { int x; float y; }; // expected-error{{use of 'X' with tag type that does not match previous declaration}} diff --git a/clang/test/SemaCXX/typedef-redecl.cpp b/clang/test/SemaCXX/typedef-redecl.cpp index 10be77cd1a6a..e38f47436d1c 100644 --- a/clang/test/SemaCXX/typedef-redecl.cpp +++ b/clang/test/SemaCXX/typedef-redecl.cpp @@ -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}} diff --git a/clang/test/SemaTemplate/class-template-decl.cpp b/clang/test/SemaTemplate/class-template-decl.cpp index 475c7b951923..c81267771297 100644 --- a/clang/test/SemaTemplate/class-template-decl.cpp +++ b/clang/test/SemaTemplate/class-template-decl.cpp @@ -14,13 +14,10 @@ extern "C" { template class D; // expected-error{{templates must have C++ linkage}} } -template class A; // expected-note{{previous template declaration is here}}\ - // expected-note{{previous use is here}} +template class A; // expected-note{{previous template declaration is here}} template class A; // expected-error{{template parameter has a different kind in template redeclaration}} -template struct A; // expected-error{{use of 'A' with tag type that does not match previous declaration}} - template class NonTypeTemplateParm; typedef int INT;