Author: rsmith Date: Tue Jan 5 21:52:10 2016 New Revision: 256907 URL: http://llvm.org/viewvc/llvm-project?rev=256907&view=rev Log: [modules] When a tag type that was imported from a module is referenced via an elaborated-type-specifier, create a declaration of it to track that the current module makes it visible too.
Added: cfe/trunk/test/Modules/tag-injection.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=256907&r1=256906&r2=256907&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jan 5 21:52:10 2016 @@ -12277,16 +12277,35 @@ Decl *Sema::ActOnTag(Scope *S, unsigned if (!Invalid) { // If this is a use, just return the declaration we found, unless // we have attributes. - - // FIXME: In the future, return a variant or some other clue - // for the consumer of this Decl to know it doesn't own it. - // For our current ASTs this shouldn't be a problem, but will - // need to be changed with DeclGroups. - if (!Attr && - ((TUK == TUK_Reference && - (!PrevTagDecl->getFriendObjectKind() || getLangOpts().MicrosoftExt)) - || TUK == TUK_Friend)) - return PrevTagDecl; + if (TUK == TUK_Reference || TUK == TUK_Friend) { + if (Attr) { + // FIXME: Diagnose these attributes. For now, we create a new + // declaration to hold them. + } else if (TUK == TUK_Reference && + (PrevTagDecl->getFriendObjectKind() == + Decl::FOK_Undeclared || + getOwningModule(PrevDecl) != + PP.getModuleContainingLocation(KWLoc)) && + SS.isEmpty()) { + // This declaration is a reference to an existing entity, but + // has different visibility from that entity: it either makes + // a friend visible or it makes a type visible in a new module. + // In either case, create a new declaration. We only do this if + // 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())) + return PrevTagDecl; + // This is in the injected scope, create a new declaration. + } else { + return PrevTagDecl; + } + } // Diagnose attempts to redefine a tag. if (TUK == TUK_Definition) { Added: cfe/trunk/test/Modules/tag-injection.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/tag-injection.cpp?rev=256907&view=auto ============================================================================== --- cfe/trunk/test/Modules/tag-injection.cpp (added) +++ cfe/trunk/test/Modules/tag-injection.cpp Tue Jan 5 21:52:10 2016 @@ -0,0 +1,22 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: touch %t/a.h +// RUN: echo 'struct X {};' > %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 -fmodules-local-submodule-visibility -std=c++11 + +#include "a.h" + +struct A { + // This use of 'struct X' makes the declaration (but not definition) of X visible. + virtual void f(struct X *p); +}; + +namespace N { + struct B : A { + void f(struct X *q) override; + }; +} + +X x; // expected-error {{definition of 'X' must be imported from module 'X.b' before it is required}} +// expected-note@b.h:1 {{here}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits