[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.

llvm-svn: 256907
This commit is contained in:
Richard Smith 2016-01-06 03:52:10 +00:00
parent 3ec882feed
commit 26dfbace82
2 changed files with 51 additions and 10 deletions

View File

@ -12277,16 +12277,35 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
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) {

View File

@ -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}}