From: David Majnemer Date: Sun, 28 Dec 2014 09:18:54 +0000 (+0000) Subject: Sema: Don't crash when an inject class name has a nested redefinition X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0ee66aad3e44d03c6e9c3fd8a5aaafde89028d94;p=clang Sema: Don't crash when an inject class name has a nested redefinition We expected the type of a TagDecl to be a TagType, not an InjectedClassNameType. Introduced a helper method, Type::getAsTagDecl, to abstract away the difference; redefine Type::getAsCXXRecordDecl to be in terms of it. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224898 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 9c3af0781f..8a77c1dd00 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1707,6 +1707,11 @@ public: /// type of a class template or class template partial specialization. CXXRecordDecl *getAsCXXRecordDecl() const; + /// \brief Retrieves the TagDecl that this type refers to, either + /// because the type is a TagType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + TagDecl *getAsTagDecl() const; + /// If this is a pointer or reference to a RecordType, return the /// CXXRecordDecl that that type refers to. /// diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index abceb8af41..e4f364d04f 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -541,10 +541,13 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { } CXXRecordDecl *Type::getAsCXXRecordDecl() const { - if (const RecordType *RT = getAs()) - return dyn_cast(RT->getDecl()); - else if (const InjectedClassNameType *Injected - = getAs()) + return dyn_cast_or_null(getAsTagDecl()); +} + +TagDecl *Type::getAsTagDecl() const { + if (const auto *TT = getAs()) + return cast(TT->getDecl()); + if (const auto *Injected = getAs()) return Injected->getDecl(); return nullptr; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d4b87ba615..834f157e04 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11599,9 +11599,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } else { // If the type is currently being defined, complain // about a nested redefinition. - const TagType *Tag - = cast(Context.getTagDeclType(PrevTagDecl)); - if (Tag->isBeingDefined()) { + auto *TD = Context.getTagDeclType(PrevTagDecl)->getAsTagDecl(); + if (TD->isBeingDefined()) { Diag(NameLoc, diag::err_nested_redefinition) << Name; Diag(PrevTagDecl->getLocation(), diag::note_previous_definition); diff --git a/test/SemaCXX/struct-class-redecl.cpp b/test/SemaCXX/struct-class-redecl.cpp index e1b95ba8d6..706ec5688b 100644 --- a/test/SemaCXX/struct-class-redecl.cpp +++ b/test/SemaCXX/struct-class-redecl.cpp @@ -7,6 +7,12 @@ union X { int x; float y; }; // expected-error{{use of 'X' with tag type that do template struct Y; // expected-note{{did you mean class here?}} template class Y { }; // expected-warning{{previously declared}} +template +struct Z { // expected-note{{previous definition is here}} + struct Z { // expected-error{{nested redefinition of 'Z'}} + }; +}; + class A; class A; // expected-note{{previous use is here}} struct A; // expected-warning{{struct 'A' was previously declared as a class}}