mirror of https://github.com/microsoft/clang.git
[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++). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@257251 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
72cc170915
commit
b3db27cd07
|
@ -11798,6 +11798,28 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC,
|
|||
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 TagSpec, TagUseKind TUK,
|
|||
// 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 TagSpec, TagUseKind TUK,
|
|||
// 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue