r256907 - [modules] When a tag type that was imported from a module is referenced via an
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 5 19:52:10 PST 2016
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 at b.h:1 {{here}}
More information about the cfe-commits
mailing list