mirror of https://github.com/microsoft/clang.git
[modules] When creating a declaration, cache its owning module immediately
rather than waiting until it's queried. Currently this is only applied to local submodule visibility mode, as we don't yet allocate storage for the owning module in non-local-visibility modules compilations. This reinstates r302965, reverted in r303037, with a fix for the reported crash, which occurred when reparenting a local declaration to be a child of a hidden imported declaration (specifically during template instantiation). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303224 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
90199139dc
commit
bd2320f5d1
|
@ -301,16 +301,6 @@ public:
|
|||
using Decl::isModulePrivate;
|
||||
using Decl::setModulePrivate;
|
||||
|
||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||
bool isHidden() const { return Hidden; }
|
||||
|
||||
/// \brief Set whether this declaration is hidden from name lookup.
|
||||
void setHidden(bool Hide) {
|
||||
assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
|
||||
"declaration with no owning module can't be hidden");
|
||||
Hidden = Hide;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is a C++ class member.
|
||||
bool isCXXClassMember() const {
|
||||
const DeclContext *DC = getDeclContext();
|
||||
|
|
|
@ -706,6 +706,20 @@ public:
|
|||
reinterpret_cast<Module **>(this)[-1] = M;
|
||||
}
|
||||
|
||||
Module *getOwningModule() const {
|
||||
return isFromASTFile() ? getImportedOwningModule() : getLocalOwningModule();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this declaration is hidden from name lookup.
|
||||
bool isHidden() const { return Hidden; }
|
||||
|
||||
/// \brief Set whether this declaration is hidden from name lookup.
|
||||
void setHidden(bool Hide) {
|
||||
assert((!Hide || isFromASTFile() || hasLocalOwningModuleStorage()) &&
|
||||
"declaration with no owning module can't be hidden");
|
||||
Hidden = Hide;
|
||||
}
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
|
|
@ -166,6 +166,11 @@ public:
|
|||
return getCompilingModule() != CMK_None;
|
||||
}
|
||||
|
||||
/// Do we need to track the owning module for a local declaration?
|
||||
bool trackLocalOwningModule() const {
|
||||
return ModulesLocalVisibility;
|
||||
}
|
||||
|
||||
bool isSignedOverflowDefined() const {
|
||||
return getSignedOverflowBehavior() == SOB_Defined;
|
||||
}
|
||||
|
|
|
@ -1467,11 +1467,9 @@ private:
|
|||
|
||||
VisibleModuleSet VisibleModules;
|
||||
|
||||
Module *CachedFakeTopLevelModule;
|
||||
|
||||
public:
|
||||
/// \brief Get the module owning an entity.
|
||||
Module *getOwningModule(Decl *Entity);
|
||||
Module *getOwningModule(Decl *Entity) { return Entity->getOwningModule(); }
|
||||
|
||||
/// \brief Make a merged definition of an existing hidden definition \p ND
|
||||
/// visible at the specified location.
|
||||
|
|
|
@ -1038,10 +1038,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
|
|||
dumpSourceRange(D->getSourceRange());
|
||||
OS << ' ';
|
||||
dumpLocation(D->getLocation());
|
||||
if (Module *M = D->getImportedOwningModule())
|
||||
if (D->isFromASTFile())
|
||||
OS << " imported";
|
||||
if (Module *M = D->getOwningModule())
|
||||
OS << " in " << M->getFullModuleName();
|
||||
else if (Module *M = D->getLocalOwningModule())
|
||||
OS << " in (local) " << M->getFullModuleName();
|
||||
if (auto *ND = dyn_cast<NamedDecl>(D))
|
||||
for (Module *M : D->getASTContext().getModulesWithMergedDefinition(
|
||||
const_cast<NamedDecl *>(ND)))
|
||||
|
|
|
@ -47,9 +47,7 @@ bool Decl::isOutOfLine() const {
|
|||
|
||||
TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx)
|
||||
: Decl(TranslationUnit, nullptr, SourceLocation()),
|
||||
DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {
|
||||
Hidden = Ctx.getLangOpts().ModulesLocalVisibility;
|
||||
}
|
||||
DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) {}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// NamedDecl Implementation
|
||||
|
|
|
@ -75,7 +75,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
|
|||
assert(!Parent || &Parent->getParentASTContext() == &Ctx);
|
||||
// With local visibility enabled, we track the owning module even for local
|
||||
// declarations.
|
||||
if (Ctx.getLangOpts().ModulesLocalVisibility) {
|
||||
if (Ctx.getLangOpts().trackLocalOwningModule()) {
|
||||
// Ensure required alignment of the resulting object by adding extra
|
||||
// padding at the start if required.
|
||||
size_t ExtraAlign =
|
||||
|
@ -83,7 +83,9 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Ctx,
|
|||
char *Buffer = reinterpret_cast<char *>(
|
||||
::operator new(ExtraAlign + sizeof(Module *) + Size + Extra, Ctx));
|
||||
Buffer += ExtraAlign;
|
||||
return new (Buffer) Module*(nullptr) + 1;
|
||||
auto *ParentModule =
|
||||
Parent ? cast<Decl>(Parent)->getOwningModule() : nullptr;
|
||||
return new (Buffer) Module*(ParentModule) + 1;
|
||||
}
|
||||
return ::operator new(Size + Extra, Ctx);
|
||||
}
|
||||
|
@ -94,7 +96,7 @@ Module *Decl::getOwningModuleSlow() const {
|
|||
}
|
||||
|
||||
bool Decl::hasLocalOwningModuleStorage() const {
|
||||
return getASTContext().getLangOpts().ModulesLocalVisibility;
|
||||
return getASTContext().getLangOpts().trackLocalOwningModule();
|
||||
}
|
||||
|
||||
const char *Decl::getDeclKindName() const {
|
||||
|
@ -273,6 +275,8 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
|
|||
getMultipleDC()->LexicalDC = DC;
|
||||
}
|
||||
Hidden = cast<Decl>(DC)->Hidden;
|
||||
if (Hidden && !isFromASTFile() && hasLocalOwningModuleStorage())
|
||||
setLocalOwningModule(cast<Decl>(DC)->getOwningModule());
|
||||
}
|
||||
|
||||
void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
|
|
|
@ -93,11 +93,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr),
|
||||
ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr),
|
||||
DictionaryWithObjectsMethod(nullptr), GlobalNewDeleteDeclared(false),
|
||||
TUKind(TUKind), NumSFINAEErrors(0), CachedFakeTopLevelModule(nullptr),
|
||||
AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false),
|
||||
NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1),
|
||||
CurrentInstantiationScope(nullptr), DisableTypoCorrection(false),
|
||||
TyposCorrected(0), AnalysisWarnings(*this),
|
||||
TUKind(TUKind), NumSFINAEErrors(0), AccessCheckingSFINAE(false),
|
||||
InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0),
|
||||
ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr),
|
||||
DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this),
|
||||
ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr),
|
||||
CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) {
|
||||
TUScope = nullptr;
|
||||
|
|
|
@ -16047,6 +16047,14 @@ void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) {
|
|||
ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules);
|
||||
|
||||
VisibleModules.setVisible(Mod, DirectiveLoc);
|
||||
|
||||
// The enclosing context is now part of this module.
|
||||
// FIXME: Consider creating a child DeclContext to hold the entities
|
||||
// lexically within the module.
|
||||
if (getLangOpts().trackLocalOwningModule()) {
|
||||
cast<Decl>(CurContext)->setHidden(true);
|
||||
cast<Decl>(CurContext)->setLocalOwningModule(Mod);
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
|
||||
|
@ -16075,6 +16083,13 @@ void Sema::ActOnModuleEnd(SourceLocation EomLoc, Module *Mod) {
|
|||
DirectiveLoc = EomLoc;
|
||||
}
|
||||
BuildModuleInclude(DirectiveLoc, Mod);
|
||||
|
||||
// Any further declarations are in whatever module we returned to.
|
||||
if (getLangOpts().trackLocalOwningModule()) {
|
||||
cast<Decl>(CurContext)->setLocalOwningModule(getCurrentModule());
|
||||
if (!getCurrentModule())
|
||||
cast<Decl>(CurContext)->setHidden(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc,
|
||||
|
|
|
@ -1326,62 +1326,6 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
|
|||
return !R.empty();
|
||||
}
|
||||
|
||||
Module *Sema::getOwningModule(Decl *Entity) {
|
||||
// If it's imported, grab its owning module.
|
||||
Module *M = Entity->getImportedOwningModule();
|
||||
if (M || !isa<NamedDecl>(Entity) || !cast<NamedDecl>(Entity)->isHidden())
|
||||
return M;
|
||||
assert(!Entity->isFromASTFile() &&
|
||||
"hidden entity from AST file has no owning module");
|
||||
|
||||
if (!getLangOpts().ModulesLocalVisibility) {
|
||||
// If we're not tracking visibility locally, the only way a declaration
|
||||
// can be hidden and local is if it's hidden because it's parent is (for
|
||||
// instance, maybe this is a lazily-declared special member of an imported
|
||||
// class).
|
||||
auto *Parent = cast<NamedDecl>(Entity->getDeclContext());
|
||||
assert(Parent->isHidden() && "unexpectedly hidden decl");
|
||||
return getOwningModule(Parent);
|
||||
}
|
||||
|
||||
// It's local and hidden; grab or compute its owning module.
|
||||
M = Entity->getLocalOwningModule();
|
||||
if (M)
|
||||
return M;
|
||||
|
||||
if (auto *Containing =
|
||||
PP.getModuleContainingLocation(Entity->getLocation())) {
|
||||
M = Containing;
|
||||
} else if (Entity->isInvalidDecl() || Entity->getLocation().isInvalid()) {
|
||||
// Don't bother tracking visibility for invalid declarations with broken
|
||||
// locations.
|
||||
cast<NamedDecl>(Entity)->setHidden(false);
|
||||
} else {
|
||||
// We need to assign a module to an entity that exists outside of any
|
||||
// module, so that we can hide it from modules that we textually enter.
|
||||
// Invent a fake module for all such entities.
|
||||
if (!CachedFakeTopLevelModule) {
|
||||
CachedFakeTopLevelModule =
|
||||
PP.getHeaderSearchInfo().getModuleMap().findOrCreateModule(
|
||||
"<top-level>", nullptr, false, false).first;
|
||||
|
||||
auto &SrcMgr = PP.getSourceManager();
|
||||
SourceLocation StartLoc =
|
||||
SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID());
|
||||
auto &TopLevel = ModuleScopes.empty()
|
||||
? VisibleModules
|
||||
: ModuleScopes[0].OuterVisibleModules;
|
||||
TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc);
|
||||
}
|
||||
|
||||
M = CachedFakeTopLevelModule;
|
||||
}
|
||||
|
||||
if (M)
|
||||
Entity->setLocalOwningModule(M);
|
||||
return M;
|
||||
}
|
||||
|
||||
void Sema::makeMergedDefinitionVisible(NamedDecl *ND) {
|
||||
if (auto *M = getCurrentModule())
|
||||
Context.mergeDefinitionIntoModule(ND, M);
|
||||
|
@ -1520,7 +1464,6 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) {
|
|||
if (SemaRef.getLangOpts().ModulesLocalVisibility) {
|
||||
DeclModule = SemaRef.getOwningModule(D);
|
||||
if (!DeclModule) {
|
||||
// getOwningModule() may have decided the declaration should not be hidden.
|
||||
assert(!D->isHidden() && "hidden decl not from a module");
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,11 @@ int m = n;
|
|||
#include "c.h"
|
||||
|
||||
#if defined(A) && !defined(ALLOW_NAME_LEAKAGE)
|
||||
#error A is defined
|
||||
#warning A is defined
|
||||
#endif
|
||||
|
||||
#define B
|
||||
|
||||
template<typename T> void b_template() {
|
||||
N::C::f(0);
|
||||
}
|
||||
|
|
|
@ -1 +1,10 @@
|
|||
#include "c.h"
|
||||
|
||||
#ifndef OTHER_H
|
||||
#define OTHER_H
|
||||
namespace N {
|
||||
struct C {
|
||||
template<typename U> static void f(U) {}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s -DIMPORT
|
||||
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -fmodule-name=x -I%S/Inputs/submodule-visibility -verify %s
|
||||
// RUN: %clang_cc1 -fimplicit-module-maps -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s
|
||||
//
|
||||
// Explicit module builds.
|
||||
// RUN: %clang_cc1 -fmodules -fmodules-local-submodule-visibility -emit-module -x c++-module-map %S/Inputs/submodule-visibility/module.modulemap -fmodule-name=other -o %t/other.pcm
|
||||
// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodules-local-submodule-visibility -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s
|
||||
// RUN: %clang_cc1 -fmodules -fmodule-map-file=%S/Inputs/submodule-visibility/module.modulemap -fmodule-file=%t/other.pcm -verify -fmodule-name=x -I%S/Inputs/submodule-visibility %s -DALLOW_TEXTUAL_NAME_LEAKAGE
|
||||
|
||||
#include "a.h"
|
||||
#include "b.h"
|
||||
|
@ -11,6 +16,8 @@
|
|||
// expected-no-diagnostics
|
||||
#elif IMPORT
|
||||
// expected-error@-6 {{could not build module 'x'}}
|
||||
#elif ALLOW_TEXTUAL_NAME_LEAKAGE
|
||||
// expected-warning@b.h:7 {{A is defined}}
|
||||
#else
|
||||
// The use of -fmodule-name=x causes us to textually include the above headers.
|
||||
// The submodule visibility rules are still applied in this case.
|
||||
|
@ -35,3 +42,5 @@ typedef struct {
|
|||
int p;
|
||||
void (*f)(int p);
|
||||
} name_for_linkage;
|
||||
|
||||
void g() { b_template<int>(); }
|
||||
|
|
Loading…
Reference in New Issue