forked from OSchip/llvm-project
[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:
parent
3ec882feed
commit
26dfbace82
|
@ -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) {
|
||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue