From f7ada5829fac99ea13daf7e568e2921341e72ad5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 11 Jun 2015 22:48:25 +0000 Subject: [PATCH] [modules] Fix assert/crash when parsing and merging a definition of a class with a base-specifier inside a namespace. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@239569 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 10 ++++------ lib/Parse/ParseDeclCXX.cpp | 5 +++-- lib/Sema/SemaDecl.cpp | 16 ++++++++++++++++ test/Modules/Inputs/submodules-merge-defs/defs.h | 6 +++--- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 03ecf96ea3..28c09a1c60 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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(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(); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 53e4a41968..55909de092 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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), diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a4a7375338..347d8070a6 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(CurContext); + CurContext = cast(D)->getDefinition(); + assert(CurContext && "skipping definition of undefined tag"); + S->setEntity(CurContext); + return Result; +} + +void Sema::ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context) { + CurContext = static_cast(Context); +} + /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. /// diff --git a/test/Modules/Inputs/submodules-merge-defs/defs.h b/test/Modules/Inputs/submodules-merge-defs/defs.h index d65e93bf72..1ab1d1a005 100644 --- a/test/Modules/Inputs/submodules-merge-defs/defs.h +++ b/test/Modules/Inputs/submodules-merge-defs/defs.h @@ -49,8 +49,8 @@ template class K = F> using I = namespace NS { struct A {}; - template struct B {}; - template struct B {}; - template<> struct B {}; + template struct B : A {}; + template struct B : B {}; + template<> struct B : B {}; inline void f() {} } -- 2.40.0