]> granicus.if.org Git - clang/commitdiff
Sema: Don't crash when an inject class name has a nested redefinition
authorDavid Majnemer <david.majnemer@gmail.com>
Sun, 28 Dec 2014 09:18:54 +0000 (09:18 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Sun, 28 Dec 2014 09:18:54 +0000 (09:18 +0000)
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

include/clang/AST/Type.h
lib/AST/Type.cpp
lib/Sema/SemaDecl.cpp
test/SemaCXX/struct-class-redecl.cpp

index 9c3af0781fc04cab80ef1a0e627eeaf1d064999a..8a77c1dd0031857e0b3653a6c2b9c94cacffc907 100644 (file)
@@ -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.
   ///
index abceb8af41faf409dd9a1ae60d764b9dc8cda363..e4f364d04f86f8d732ec64c095b5bafebc82d3d4 100644 (file)
@@ -541,10 +541,13 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
 }
 
 CXXRecordDecl *Type::getAsCXXRecordDecl() const {
-  if (const RecordType *RT = getAs<RecordType>())
-    return dyn_cast<CXXRecordDecl>(RT->getDecl());
-  else if (const InjectedClassNameType *Injected
-                                  = getAs<InjectedClassNameType>())
+  return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl());
+}
+
+TagDecl *Type::getAsTagDecl() const {
+  if (const auto *TT = getAs<TagType>())
+    return cast<TagDecl>(TT->getDecl());
+  if (const auto *Injected = getAs<InjectedClassNameType>())
     return Injected->getDecl();
 
   return nullptr;
index d4b87ba615e01738915c7eb015db84e59e839682..834f157e04f4cb5024f4aaca2c7bdd9a0a855e3c 100644 (file)
@@ -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<TagType>(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);
index e1b95ba8d63ce075ee38b6abf3a848f26f017c44..706ec5688ba53a68ec6f12a73f6389eef6f74db1 100644 (file)
@@ -7,6 +7,12 @@ union X { int x; float y; }; // expected-error{{use of 'X' with tag type that do
 template<typename T> struct Y; // expected-note{{did you mean class here?}}
 template<class U> class Y { }; // expected-warning{{previously declared}}
 
+template <typename>
+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}}