Author: rsmith Date: Sat Jan 9 00:58:48 2016 New Revision: 257251 URL: http://llvm.org/viewvc/llvm-project?rev=257251&view=rev Log: [modules] If we're treating an elaborated-type-specifier as if it introduces a tag (because the previous declaration was found in a different module), inject the tag into the appropriate scope (that is, the enclosing scope if we're in a function prototype scope in C++).
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/test/Modules/tag-injection.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=257251&r1=257250&r2=257251&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Jan 9 00:58:48 2016 @@ -11798,6 +11798,28 @@ static bool isAcceptableTagRedeclContext return false; } +/// Find the DeclContext in which a tag is implicitly declared if we see an +/// elaborated type specifier in the specified context, and lookup finds +/// nothing. +static DeclContext *getTagInjectionContext(DeclContext *DC) { + while (!DC->isFileContext() && !DC->isFunctionOrMethod()) + DC = DC->getParent(); + return DC; +} + +/// Find the Scope in which a tag is implicitly declared if we see an +/// elaborated type specifier in the specified context, and lookup finds +/// nothing. +static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { + while (S->isClassScope() || + (LangOpts.CPlusPlus && + S->isFunctionPrototypeScope()) || + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && S->getEntity()->isTransparentContext())) + S = S->getParent(); + return S; +} + /// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a @@ -12114,16 +12136,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned // Find the context where we'll be declaring the tag. // FIXME: We would like to maintain the current DeclContext as the // lexical context, - while (!SearchDC->isFileContext() && !SearchDC->isFunctionOrMethod()) - SearchDC = SearchDC->getParent(); + SearchDC = getTagInjectionContext(SearchDC); // Find the scope where we'll be declaring the tag. - while (S->isClassScope() || - (getLangOpts().CPlusPlus && - S->isFunctionPrototypeScope()) || - ((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && S->getEntity()->isTransparentContext())) - S = S->getParent(); + S = getTagInjectionScope(S, getLangOpts()); } else { assert(TUK == TUK_Friend); // C++ [namespace.memdef]p3: @@ -12293,14 +12309,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned // the declaration would have meant the same thing if no prior // declaration were found, that is, if it was found in the same // scope where we would have injected a declaration. - DeclContext *InjectedDC = CurContext; - while (!InjectedDC->isFileContext() && - !InjectedDC->isFunctionOrMethod()) - InjectedDC = InjectedDC->getParent(); - if (!InjectedDC->getRedeclContext()->Equals( - PrevDecl->getDeclContext()->getRedeclContext())) + if (!getTagInjectionContext(CurContext) + ->getRedeclContext() + ->Equals(PrevDecl->getDeclContext()->getRedeclContext())) return PrevTagDecl; - // This is in the injected scope, create a new declaration. + // This is in the injected scope, create a new declaration in + // that scope. + S = getTagInjectionScope(S, getLangOpts()); } else { return PrevTagDecl; } Modified: cfe/trunk/test/Modules/tag-injection.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/tag-injection.cpp?rev=257251&r1=257250&r2=257251&view=diff ============================================================================== --- cfe/trunk/test/Modules/tag-injection.cpp (original) +++ cfe/trunk/test/Modules/tag-injection.cpp Sat Jan 9 00:58:48 2016 @@ -1,12 +1,15 @@ // RUN: rm -rf %t // RUN: mkdir %t -// RUN: touch %t/a.h -// RUN: echo 'struct X {};' > %t/b.h +// RUN: echo 'struct tm;' > %t/a.h +// RUN: echo 'struct X {}; void foo(struct tm*);' > %t/b.h // RUN: echo 'module X { module a { header "a.h" } module b { header "b.h" } }' > %t/x.modulemap +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -std=c++11 // RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -x c++ -fmodule-map-file=%t/x.modulemap %s -I%t -verify -fmodules-local-submodule-visibility -std=c++11 #include "a.h" +using ::tm; + struct A { // This use of 'struct X' makes the declaration (but not definition) of X visible. virtual void f(struct X *p); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits