r257251 - [modules] If we're treating an elaborated-type-specifier as if it introduces a
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 8 22:58:49 PST 2016
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);
More information about the cfe-commits
mailing list