]> granicus.if.org Git - clang/commitdiff
[modules] Fix assert/crash when parsing and merging a definition of a class with...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 11 Jun 2015 22:48:25 +0000 (22:48 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 11 Jun 2015 22:48:25 +0000 (22:48 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@239569 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/Sema.h
lib/Parse/ParseDeclCXX.cpp
lib/Sema/SemaDecl.cpp
test/Modules/Inputs/submodules-merge-defs/defs.h

index 03ecf96ea30c1d2dc95a4521d2003be698b22581..28c09a1c60497af2a40711d3086a371116041ed4 100644 (file)
@@ -1850,10 +1850,10 @@ public:
   /// struct, or union).
   void ActOnTagStartDefinition(Scope *S, Decl *TagDecl);
 
+  typedef void *SkippedDefinitionContext;
+
   /// \brief Invoked when we enter a tag definition that we're skipping.
-  void ActOnTagStartSkippedDefinition(Scope *S, Decl *TD) {
-    PushDeclContext(S, cast<DeclContext>(TD));
-  }
+  SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD);
 
   Decl *ActOnObjCContainerStartDefinition(Decl *IDecl);
 
@@ -1870,9 +1870,7 @@ public:
   void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl,
                                 SourceLocation RBraceLoc);
 
-  void ActOnTagFinishSkippedDefinition() {
-    PopDeclContext();
-  }
+  void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context);
 
   void ActOnObjCContainerFinishDefinition();
 
index 53e4a419682e3b77bedab62673060d0808e44937..55909de0928bdf63246faca9f9357c3ff969095d 100644 (file)
@@ -2724,12 +2724,13 @@ void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
     ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
     ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
                                       TagType == DeclSpec::TST_interface);
-    Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl);
+    auto OldContext =
+        Actions.ActOnTagStartSkippedDefinition(getCurScope(), TagDecl);
 
     // Parse the bases but don't attach them to the class.
     ParseBaseClause(nullptr);
 
-    Actions.ActOnTagFinishSkippedDefinition();
+    Actions.ActOnTagFinishSkippedDefinition(OldContext);
 
     if (!Tok.is(tok::l_brace)) {
       Diag(PP.getLocForEndOfToken(PrevTokLocation),
index a4a73753383607801bc7b61cdebc43deec149928..347d8070a6b100098dfe4e1f9035e0615749273a 100644 (file)
@@ -1081,6 +1081,22 @@ void Sema::PopDeclContext() {
   assert(CurContext && "Popped translation unit!");
 }
 
+Sema::SkippedDefinitionContext Sema::ActOnTagStartSkippedDefinition(Scope *S,
+                                                                    Decl *D) {
+  // Unlike PushDeclContext, the context to which we return is not necessarily
+  // the containing DC of TD, because the new context will be some pre-existing
+  // TagDecl definition instead of a fresh one.
+  auto Result = static_cast<SkippedDefinitionContext>(CurContext);
+  CurContext = cast<TagDecl>(D)->getDefinition();
+  assert(CurContext && "skipping definition of undefined tag");
+  S->setEntity(CurContext);
+  return Result;
+}
+
+void Sema::ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context) {
+  CurContext = static_cast<decltype(CurContext)>(Context);
+}
+
 /// EnterDeclaratorContext - Used when we must lookup names in the context
 /// of a declarator's nested name specifier.
 ///
index d65e93bf72b6170b7bc9eaeb3f4ef71616104111..1ab1d1a005be3b961a20db84994c61fb25251bc9 100644 (file)
@@ -49,8 +49,8 @@ template<typename T = int, int N = 3, template<typename> class K = F> using I =
 
 namespace NS {
   struct A {};
-  template<typename T> struct B {};
-  template<typename T> struct B<T*> {};
-  template<> struct B<int> {};
+  template<typename T> struct B : A {};
+  template<typename T> struct B<T*> : B<char> {};
+  template<> struct B<int> : B<int*> {};
   inline void f() {}
 }