mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 14:26:09 +00:00
[modules] Remove redundant import of lexical decls when building a lookup table
for a DeclContext, and fix propagation of exception specifications along redeclaration chains. This reverts r232905, r232907, and r232907, which reverted r232793, r232853, and r232853. One additional change is present here to resolve issues with LLDB: distinguish between whether lexical decls missing from the lookup table are local or are provided by the external AST source, and still look in the external source if that's where they came from. llvm-svn: 232928
This commit is contained in:
parent
1e1b0f732a
commit
9e2341d093
@ -1096,14 +1096,21 @@ class DeclContext {
|
||||
/// another lookup.
|
||||
mutable bool NeedToReconcileExternalVisibleStorage : 1;
|
||||
|
||||
/// \brief If \c true, this context may have local lexical declarations
|
||||
/// that are missing from the lookup table.
|
||||
mutable bool HasLazyLocalLexicalLookups : 1;
|
||||
|
||||
/// \brief If \c true, the external source may have lexical declarations
|
||||
/// that are missing from the lookup table.
|
||||
mutable bool HasLazyExternalLexicalLookups : 1;
|
||||
|
||||
/// \brief Pointer to the data structure used to lookup declarations
|
||||
/// within this context (or a DependentStoredDeclsMap if this is a
|
||||
/// dependent context), and a bool indicating whether we have lazily
|
||||
/// omitted any declarations from the map. We maintain the invariant
|
||||
/// that, if the map contains an entry for a DeclarationName (and we
|
||||
/// haven't lazily omitted anything), then it contains all relevant
|
||||
/// entries for that name.
|
||||
mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr;
|
||||
/// dependent context). We maintain the invariant that, if the map
|
||||
/// contains an entry for a DeclarationName (and we haven't lazily
|
||||
/// omitted anything), then it contains all relevant entries for that
|
||||
/// name (modulo the hasExternalDecls() flag).
|
||||
mutable StoredDeclsMap *LookupPtr;
|
||||
|
||||
protected:
|
||||
/// FirstDecl - The first declaration stored within this declaration
|
||||
@ -1129,8 +1136,9 @@ protected:
|
||||
DeclContext(Decl::Kind K)
|
||||
: DeclKind(K), ExternalLexicalStorage(false),
|
||||
ExternalVisibleStorage(false),
|
||||
NeedToReconcileExternalVisibleStorage(false), LookupPtr(nullptr, false),
|
||||
FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
NeedToReconcileExternalVisibleStorage(false),
|
||||
HasLazyLocalLexicalLookups(false), HasLazyExternalLexicalLookups(false),
|
||||
LookupPtr(nullptr), FirstDecl(nullptr), LastDecl(nullptr) {}
|
||||
|
||||
public:
|
||||
~DeclContext();
|
||||
@ -1656,17 +1664,22 @@ public:
|
||||
inline ddiag_range ddiags() const;
|
||||
|
||||
// Low-level accessors
|
||||
|
||||
/// \brief Mark the lookup table as needing to be built. This should be
|
||||
/// used only if setHasExternalLexicalStorage() has been called on any
|
||||
/// decl context for which this is the primary context.
|
||||
|
||||
/// \brief Mark that there are external lexical declarations that we need
|
||||
/// to include in our lookup table (and that are not available as external
|
||||
/// visible lookups). These extra lookup results will be found by walking
|
||||
/// the lexical declarations of this context. This should be used only if
|
||||
/// setHasExternalLexicalStorage() has been called on any decl context for
|
||||
/// which this is the primary context.
|
||||
void setMustBuildLookupTable() {
|
||||
LookupPtr.setInt(true);
|
||||
assert(this == getPrimaryContext() &&
|
||||
"should only be called on primary context");
|
||||
HasLazyExternalLexicalLookups = true;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the internal representation of the lookup structure.
|
||||
/// This may omit some names if we are lazily building the structure.
|
||||
StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); }
|
||||
StoredDeclsMap *getLookupPtr() const { return LookupPtr; }
|
||||
|
||||
/// \brief Ensure the lookup structure is fully-built and return it.
|
||||
StoredDeclsMap *buildLookup();
|
||||
@ -1689,7 +1702,7 @@ public:
|
||||
/// declarations visible in this context.
|
||||
void setHasExternalVisibleStorage(bool ES = true) {
|
||||
ExternalVisibleStorage = ES;
|
||||
if (ES && LookupPtr.getPointer())
|
||||
if (ES && LookupPtr)
|
||||
NeedToReconcileExternalVisibleStorage = true;
|
||||
}
|
||||
|
||||
@ -1722,8 +1735,6 @@ private:
|
||||
friend class DependentDiagnostic;
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
template<decl_iterator (DeclContext::*Begin)() const,
|
||||
decl_iterator (DeclContext::*End)() const>
|
||||
void buildLookupImpl(DeclContext *DCtx, bool Internal);
|
||||
void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
bool Rediscoverable);
|
||||
|
@ -446,6 +446,12 @@ private:
|
||||
/// that we needed but hadn't loaded yet.
|
||||
llvm::DenseMap<void *, PendingFakeDefinitionKind> PendingFakeDefinitionData;
|
||||
|
||||
/// \brief Exception specification updates that have been loaded but not yet
|
||||
/// propagated across the relevant redeclaration chain. The map key is the
|
||||
/// canonical declaration (used only for deduplication) and the value is a
|
||||
/// declaration that has an exception specification.
|
||||
llvm::SmallMapVector<Decl *, FunctionDecl *, 4> PendingExceptionSpecUpdates;
|
||||
|
||||
struct ReplacedDeclInfo {
|
||||
ModuleFile *Mod;
|
||||
uint64_t Offset;
|
||||
@ -948,6 +954,11 @@ private:
|
||||
llvm::MapVector<IdentifierInfo *, SmallVector<uint32_t, 4> >
|
||||
PendingIdentifierInfos;
|
||||
|
||||
/// \brief The set of lookup results that we have faked in order to support
|
||||
/// merging of partially deserialized decls but that we have not yet removed.
|
||||
llvm::SmallMapVector<IdentifierInfo *, SmallVector<NamedDecl*, 2>, 16>
|
||||
PendingFakeLookupResults;
|
||||
|
||||
/// \brief The generation number of each identifier, which keeps track of
|
||||
/// the last time we loaded information about this identifier.
|
||||
llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration;
|
||||
@ -1174,6 +1185,18 @@ private:
|
||||
/// merged into its redecl chain.
|
||||
Decl *getMostRecentExistingDecl(Decl *D);
|
||||
|
||||
template <typename Fn>
|
||||
void forEachFormerlyCanonicalImportedDecl(const Decl *D, Fn Visit) {
|
||||
D = D->getCanonicalDecl();
|
||||
if (D->isFromASTFile())
|
||||
Visit(D);
|
||||
|
||||
auto It = MergedDecls.find(const_cast<Decl*>(D));
|
||||
if (It != MergedDecls.end())
|
||||
for (auto ID : It->second)
|
||||
Visit(GetExistingDecl(ID));
|
||||
}
|
||||
|
||||
RecordLocation DeclCursorForID(serialization::DeclID ID,
|
||||
unsigned &RawLocation);
|
||||
void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D);
|
||||
|
@ -7946,7 +7946,7 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
|
||||
while (LexicalContext && !isa<FunctionDecl>(LexicalContext))
|
||||
LexicalContext = LexicalContext->getLexicalParent();
|
||||
|
||||
// Let the static local variable inherit it's linkage from the nearest
|
||||
// Let the static local variable inherit its linkage from the nearest
|
||||
// enclosing function.
|
||||
if (LexicalContext)
|
||||
StaticLocalLinkage =
|
||||
|
@ -1011,10 +1011,10 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
|
||||
/// built a lookup map. For every name in the map, pull in the new names from
|
||||
/// the external storage.
|
||||
void DeclContext::reconcileExternalVisibleStorage() const {
|
||||
assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
|
||||
assert(NeedToReconcileExternalVisibleStorage && LookupPtr);
|
||||
NeedToReconcileExternalVisibleStorage = false;
|
||||
|
||||
for (auto &Lookup : *LookupPtr.getPointer())
|
||||
for (auto &Lookup : *LookupPtr)
|
||||
Lookup.second.setHasExternalDecls();
|
||||
}
|
||||
|
||||
@ -1027,10 +1027,13 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
|
||||
|
||||
// Notify that we have a DeclContext that is initializing.
|
||||
ExternalASTSource::Deserializing ADeclContext(Source);
|
||||
|
||||
|
||||
ExternalLexicalStorage = false;
|
||||
bool HadLazyExternalLexicalLookups = HasLazyExternalLexicalLookups;
|
||||
HasLazyExternalLexicalLookups = false;
|
||||
|
||||
// Load the external declarations, if any.
|
||||
SmallVector<Decl*, 64> Decls;
|
||||
ExternalLexicalStorage = false;
|
||||
switch (Source->FindExternalLexicalDecls(this, Decls)) {
|
||||
case ELR_Success:
|
||||
break;
|
||||
@ -1043,6 +1046,9 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
|
||||
if (Decls.empty())
|
||||
return;
|
||||
|
||||
if (HadLazyExternalLexicalLookups)
|
||||
HasLazyLocalLexicalLookups = true;
|
||||
|
||||
// We may have already loaded just the fields of this record, in which case
|
||||
// we need to ignore them.
|
||||
bool FieldsAlreadyLoaded = false;
|
||||
@ -1065,7 +1071,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
DeclarationName Name) {
|
||||
ASTContext &Context = DC->getParentASTContext();
|
||||
StoredDeclsMap *Map;
|
||||
if (!(Map = DC->LookupPtr.getPointer()))
|
||||
if (!(Map = DC->LookupPtr))
|
||||
Map = DC->CreateStoredDeclsMap(Context);
|
||||
if (DC->NeedToReconcileExternalVisibleStorage)
|
||||
DC->reconcileExternalVisibleStorage();
|
||||
@ -1081,7 +1087,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
|
||||
ArrayRef<NamedDecl*> Decls) {
|
||||
ASTContext &Context = DC->getParentASTContext();
|
||||
StoredDeclsMap *Map;
|
||||
if (!(Map = DC->LookupPtr.getPointer()))
|
||||
if (!(Map = DC->LookupPtr))
|
||||
Map = DC->CreateStoredDeclsMap(Context);
|
||||
if (DC->NeedToReconcileExternalVisibleStorage)
|
||||
DC->reconcileExternalVisibleStorage();
|
||||
@ -1175,7 +1181,7 @@ void DeclContext::removeDecl(Decl *D) {
|
||||
// Remove only decls that have a name
|
||||
if (!ND->getDeclName()) return;
|
||||
|
||||
StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer();
|
||||
StoredDeclsMap *Map = getPrimaryContext()->LookupPtr;
|
||||
if (!Map) return;
|
||||
|
||||
StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName());
|
||||
@ -1263,32 +1269,28 @@ static bool shouldBeHidden(NamedDecl *D) {
|
||||
StoredDeclsMap *DeclContext::buildLookup() {
|
||||
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
|
||||
|
||||
// FIXME: Should we keep going if hasExternalVisibleStorage?
|
||||
if (!LookupPtr.getInt())
|
||||
return LookupPtr.getPointer();
|
||||
if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups)
|
||||
return LookupPtr;
|
||||
|
||||
if (HasLazyExternalLexicalLookups)
|
||||
LoadLexicalDeclsFromExternalStorage();
|
||||
|
||||
SmallVector<DeclContext *, 2> Contexts;
|
||||
collectAllContexts(Contexts);
|
||||
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
|
||||
buildLookupImpl<&DeclContext::decls_begin,
|
||||
&DeclContext::decls_end>(Contexts[I], false);
|
||||
buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
|
||||
|
||||
// We no longer have any lazy decls.
|
||||
LookupPtr.setInt(false);
|
||||
return LookupPtr.getPointer();
|
||||
HasLazyLocalLexicalLookups = false;
|
||||
return LookupPtr;
|
||||
}
|
||||
|
||||
/// buildLookupImpl - Build part of the lookup data structure for the
|
||||
/// declarations contained within DCtx, which will either be this
|
||||
/// DeclContext, a DeclContext linked to it, or a transparent context
|
||||
/// nested within it.
|
||||
template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
|
||||
DeclContext::decl_iterator (DeclContext::*End)() const>
|
||||
void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
|
||||
for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
|
||||
I != E; ++I) {
|
||||
Decl *D = *I;
|
||||
|
||||
for (Decl *D : DCtx->noload_decls()) {
|
||||
// Insert this declaration into the lookup structure, but only if
|
||||
// it's semantically within its decl context. Any other decls which
|
||||
// should be found in this context are added eagerly.
|
||||
@ -1309,7 +1311,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) {
|
||||
// context (recursively).
|
||||
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
|
||||
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
|
||||
buildLookupImpl<Begin, End>(InnerCtx, Internal);
|
||||
buildLookupImpl(InnerCtx, Internal);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1337,9 +1339,9 @@ DeclContext::lookup(DeclarationName Name) const {
|
||||
if (NeedToReconcileExternalVisibleStorage)
|
||||
reconcileExternalVisibleStorage();
|
||||
|
||||
StoredDeclsMap *Map = LookupPtr.getPointer();
|
||||
StoredDeclsMap *Map = LookupPtr;
|
||||
|
||||
if (LookupPtr.getInt())
|
||||
if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
|
||||
// FIXME: Make buildLookup const?
|
||||
Map = const_cast<DeclContext*>(this)->buildLookup();
|
||||
|
||||
@ -1353,7 +1355,7 @@ DeclContext::lookup(DeclarationName Name) const {
|
||||
return R.first->second.getLookupResult();
|
||||
|
||||
if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) {
|
||||
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
|
||||
if (StoredDeclsMap *Map = LookupPtr) {
|
||||
StoredDeclsMap::iterator I = Map->find(Name);
|
||||
if (I != Map->end())
|
||||
return I->second.getLookupResult();
|
||||
@ -1363,8 +1365,8 @@ DeclContext::lookup(DeclarationName Name) const {
|
||||
return lookup_result();
|
||||
}
|
||||
|
||||
StoredDeclsMap *Map = LookupPtr.getPointer();
|
||||
if (LookupPtr.getInt())
|
||||
StoredDeclsMap *Map = LookupPtr;
|
||||
if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups)
|
||||
Map = const_cast<DeclContext*>(this)->buildLookup();
|
||||
|
||||
if (!Map)
|
||||
@ -1388,26 +1390,18 @@ DeclContext::noload_lookup(DeclarationName Name) {
|
||||
if (PrimaryContext != this)
|
||||
return PrimaryContext->noload_lookup(Name);
|
||||
|
||||
StoredDeclsMap *Map = LookupPtr.getPointer();
|
||||
if (LookupPtr.getInt()) {
|
||||
// Carefully build the lookup map, without deserializing anything.
|
||||
// If we have any lazy lexical declarations not in our lookup map, add them
|
||||
// now. Don't import any external declarations, not even if we know we have
|
||||
// some missing from the external visible lookups.
|
||||
if (HasLazyLocalLexicalLookups) {
|
||||
SmallVector<DeclContext *, 2> Contexts;
|
||||
collectAllContexts(Contexts);
|
||||
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
|
||||
buildLookupImpl<&DeclContext::noload_decls_begin,
|
||||
&DeclContext::noload_decls_end>(Contexts[I], true);
|
||||
|
||||
// We no longer have any lazy decls.
|
||||
LookupPtr.setInt(false);
|
||||
|
||||
// There may now be names for which we have local decls but are
|
||||
// missing the external decls. FIXME: Just set the hasExternalDecls
|
||||
// flag on those names that have external decls.
|
||||
NeedToReconcileExternalVisibleStorage = true;
|
||||
|
||||
Map = LookupPtr.getPointer();
|
||||
buildLookupImpl(Contexts[I], hasExternalVisibleStorage());
|
||||
HasLazyLocalLexicalLookups = false;
|
||||
}
|
||||
|
||||
StoredDeclsMap *Map = LookupPtr;
|
||||
if (!Map)
|
||||
return lookup_result();
|
||||
|
||||
@ -1429,8 +1423,9 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
|
||||
}
|
||||
|
||||
// If we have a lookup table, check there first. Maybe we'll get lucky.
|
||||
if (Name && !LookupPtr.getInt()) {
|
||||
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
|
||||
// FIXME: Should we be checking these flags on the primary context?
|
||||
if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) {
|
||||
if (StoredDeclsMap *Map = LookupPtr) {
|
||||
StoredDeclsMap::iterator Pos = Map->find(Name);
|
||||
if (Pos != Map->end()) {
|
||||
Results.insert(Results.end(),
|
||||
@ -1443,6 +1438,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
|
||||
|
||||
// Slow case: grovel through the declarations in our chain looking for
|
||||
// matches.
|
||||
// FIXME: If we have lazy external declarations, this will not find them!
|
||||
// FIXME: Should we CollectAllContexts and walk them all here?
|
||||
for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
|
||||
if (ND->getDeclName() == Name)
|
||||
@ -1523,7 +1520,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
// FIXME: As a performance hack, don't add such decls into the translation
|
||||
// unit unless we're in C++, since qualified lookup into the TU is never
|
||||
// performed.
|
||||
if (LookupPtr.getPointer() || hasExternalVisibleStorage() ||
|
||||
if (LookupPtr || hasExternalVisibleStorage() ||
|
||||
((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) &&
|
||||
(getParentASTContext().getLangOpts().CPlusPlus ||
|
||||
!isTranslationUnit()))) {
|
||||
@ -1533,7 +1530,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
buildLookup();
|
||||
makeDeclVisibleInContextImpl(D, Internal);
|
||||
} else {
|
||||
LookupPtr.setInt(true);
|
||||
HasLazyLocalLexicalLookups = true;
|
||||
}
|
||||
|
||||
// If we are a transparent context or inline namespace, insert into our
|
||||
@ -1551,7 +1548,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
|
||||
|
||||
void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
|
||||
// Find or create the stored declaration map.
|
||||
StoredDeclsMap *Map = LookupPtr.getPointer();
|
||||
StoredDeclsMap *Map = LookupPtr;
|
||||
if (!Map) {
|
||||
ASTContext *C = &getParentASTContext();
|
||||
Map = CreateStoredDeclsMap(*C);
|
||||
@ -1613,7 +1610,7 @@ DeclContext::udir_range DeclContext::using_directives() const {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
|
||||
assert(!LookupPtr.getPointer() && "context already has a decls map");
|
||||
assert(!LookupPtr && "context already has a decls map");
|
||||
assert(getPrimaryContext() == this &&
|
||||
"creating decls map on non-primary context");
|
||||
|
||||
@ -1625,7 +1622,7 @@ StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const {
|
||||
M = new StoredDeclsMap();
|
||||
M->Previous = C.LastSDM;
|
||||
C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent);
|
||||
LookupPtr.setPointer(M);
|
||||
LookupPtr = M;
|
||||
return M;
|
||||
}
|
||||
|
||||
@ -1657,11 +1654,11 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C,
|
||||
assert(Parent->isDependentContext()
|
||||
&& "cannot iterate dependent diagnostics of non-dependent context");
|
||||
Parent = Parent->getPrimaryContext();
|
||||
if (!Parent->LookupPtr.getPointer())
|
||||
if (!Parent->LookupPtr)
|
||||
Parent->CreateStoredDeclsMap(C);
|
||||
|
||||
DependentStoredDeclsMap *Map
|
||||
= static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer());
|
||||
DependentStoredDeclsMap *Map =
|
||||
static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr);
|
||||
|
||||
// Allocate the copy of the PartialDiagnostic via the ASTContext's
|
||||
// BumpPtrAllocator, rather than the ASTContext itself.
|
||||
|
@ -98,7 +98,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S,
|
||||
bool AllowInlineNamespace) const {
|
||||
Ctx = Ctx->getRedeclContext();
|
||||
|
||||
if (Ctx->isFunctionOrMethod() || S->isFunctionPrototypeScope()) {
|
||||
if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) {
|
||||
// Ignore the scopes associated within transparent declaration contexts.
|
||||
while (S->getEntity() && S->getEntity()->isTransparentContext())
|
||||
S = S->getParent();
|
||||
|
@ -167,13 +167,13 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
|
||||
void
|
||||
Sema::UpdateExceptionSpec(FunctionDecl *FD,
|
||||
const FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||
for (auto *Redecl : FD->redecls())
|
||||
Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
|
||||
|
||||
// If we've fully resolved the exception specification, notify listeners.
|
||||
if (!isUnresolvedExceptionSpec(ESI.Type))
|
||||
if (auto *Listener = getASTMutationListener())
|
||||
Listener->ResolvedExceptionSpec(FD);
|
||||
|
||||
for (auto *Redecl : FD->redecls())
|
||||
Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI);
|
||||
}
|
||||
|
||||
/// Determine whether a function has an implicitly-generated exception
|
||||
|
@ -3021,17 +3021,45 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result,
|
||||
if (Visited.visitedContext(Ctx->getPrimaryContext()))
|
||||
return;
|
||||
|
||||
// Outside C++, lookup results for the TU live on identifiers.
|
||||
if (isa<TranslationUnitDecl>(Ctx) &&
|
||||
!Result.getSema().getLangOpts().CPlusPlus) {
|
||||
auto &S = Result.getSema();
|
||||
auto &Idents = S.Context.Idents;
|
||||
|
||||
// Ensure all external identifiers are in the identifier table.
|
||||
if (IdentifierInfoLookup *External = Idents.getExternalIdentifierLookup()) {
|
||||
std::unique_ptr<IdentifierIterator> Iter(External->getIdentifiers());
|
||||
for (StringRef Name = Iter->Next(); !Name.empty(); Name = Iter->Next())
|
||||
Idents.get(Name);
|
||||
}
|
||||
|
||||
// Walk all lookup results in the TU for each identifier.
|
||||
for (const auto &Ident : Idents) {
|
||||
for (auto I = S.IdResolver.begin(Ident.getValue()),
|
||||
E = S.IdResolver.end();
|
||||
I != E; ++I) {
|
||||
if (S.IdResolver.isDeclInScope(*I, Ctx)) {
|
||||
if (NamedDecl *ND = Result.getAcceptableDecl(*I)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx))
|
||||
Result.getSema().ForceDeclarationOfImplicitMembers(Class);
|
||||
|
||||
// Enumerate all of the results in this context.
|
||||
for (const auto &R : Ctx->lookups()) {
|
||||
for (auto *I : R) {
|
||||
if (NamedDecl *ND = dyn_cast<NamedDecl>(I)) {
|
||||
if ((ND = Result.getAcceptableDecl(ND))) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
for (auto *D : R) {
|
||||
if (auto *ND = Result.getAcceptableDecl(D)) {
|
||||
Consumer.FoundDecl(ND, Visited.checkHidden(ND), Ctx, InBaseClass);
|
||||
Visited.add(ND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//===--- ASTReader.cpp - AST File Reader ----------------------------------===//
|
||||
//===-- ASTReader.cpp - AST File Reader ----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -2835,6 +2835,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) {
|
||||
}
|
||||
|
||||
case EAGERLY_DESERIALIZED_DECLS:
|
||||
// FIXME: Skip reading this record if our ASTConsumer doesn't care
|
||||
// about "interesting" decls (for instance, if we're building a module).
|
||||
for (unsigned I = 0, N = Record.size(); I != N; ++I)
|
||||
EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I]));
|
||||
break;
|
||||
@ -6832,6 +6834,12 @@ void ASTReader::PassInterestingDeclsToConsumer() {
|
||||
SaveAndRestore<bool> GuardPassingDeclsToConsumer(PassingDeclsToConsumer,
|
||||
true);
|
||||
|
||||
// Ensure that we've loaded all potentially-interesting declarations
|
||||
// that need to be eagerly loaded.
|
||||
for (auto ID : EagerlyDeserializedDecls)
|
||||
GetDecl(ID);
|
||||
EagerlyDeserializedDecls.clear();
|
||||
|
||||
while (!InterestingDecls.empty()) {
|
||||
Decl *D = InterestingDecls.front();
|
||||
InterestingDecls.pop_front();
|
||||
@ -6850,17 +6858,8 @@ void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
|
||||
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
|
||||
this->Consumer = Consumer;
|
||||
|
||||
if (!Consumer)
|
||||
return;
|
||||
|
||||
for (unsigned I = 0, N = EagerlyDeserializedDecls.size(); I != N; ++I) {
|
||||
// Force deserialization of this decl, which will cause it to be queued for
|
||||
// passing to the consumer.
|
||||
GetDecl(EagerlyDeserializedDecls[I]);
|
||||
}
|
||||
EagerlyDeserializedDecls.clear();
|
||||
|
||||
PassInterestingDeclsToConsumer();
|
||||
if (Consumer)
|
||||
PassInterestingDeclsToConsumer();
|
||||
|
||||
if (DeserializationListener)
|
||||
DeserializationListener->ReaderInitialized(this);
|
||||
@ -8618,6 +8617,13 @@ void ASTReader::FinishedDeserializing() {
|
||||
--NumCurrentElementsDeserializing;
|
||||
|
||||
if (NumCurrentElementsDeserializing == 0) {
|
||||
// Propagate exception specification updates along redeclaration chains.
|
||||
for (auto Update : PendingExceptionSpecUpdates) {
|
||||
auto *FPT = Update.second->getType()->castAs<FunctionProtoType>();
|
||||
SemaObj->UpdateExceptionSpec(Update.second,
|
||||
FPT->getExtProtoInfo().ExceptionSpec);
|
||||
}
|
||||
|
||||
diagnoseOdrViolations();
|
||||
|
||||
// We are not in recursive loading, so it's safe to pass the "interesting"
|
||||
@ -8628,7 +8634,15 @@ void ASTReader::FinishedDeserializing() {
|
||||
}
|
||||
|
||||
void ASTReader::pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name) {
|
||||
D = D->getMostRecentDecl();
|
||||
if (IdentifierInfo *II = Name.getAsIdentifierInfo()) {
|
||||
// Remove any fake results before adding any real ones.
|
||||
auto It = PendingFakeLookupResults.find(II);
|
||||
if (It != PendingFakeLookupResults.end()) {
|
||||
for (auto *ND : PendingFakeLookupResults[II])
|
||||
SemaObj->IdResolver.RemoveDecl(ND);
|
||||
PendingFakeLookupResults.erase(It);
|
||||
}
|
||||
}
|
||||
|
||||
if (SemaObj->IdResolver.tryAddTopLevelDecl(D, Name) && SemaObj->TUScope) {
|
||||
SemaObj->TUScope->AddDecl(D);
|
||||
|
@ -228,9 +228,11 @@ namespace clang {
|
||||
|
||||
template <typename DeclT>
|
||||
static void attachPreviousDeclImpl(ASTReader &Reader,
|
||||
Redeclarable<DeclT> *D, Decl *Previous);
|
||||
Redeclarable<DeclT> *D, Decl *Previous,
|
||||
Decl *Canon);
|
||||
static void attachPreviousDeclImpl(ASTReader &Reader, ...);
|
||||
static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous);
|
||||
static void attachPreviousDecl(ASTReader &Reader, Decl *D, Decl *Previous,
|
||||
Decl *Canon);
|
||||
|
||||
template <typename DeclT>
|
||||
static void attachLatestDeclImpl(Redeclarable<DeclT> *D, Decl *Latest);
|
||||
@ -2621,8 +2623,11 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() {
|
||||
if (needsAnonymousDeclarationNumber(New)) {
|
||||
setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(),
|
||||
AnonymousDeclNumber, New);
|
||||
} else if (DC->isTranslationUnit() && Reader.SemaObj) {
|
||||
Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name);
|
||||
} else if (DC->isTranslationUnit() && Reader.SemaObj &&
|
||||
!Reader.getContext().getLangOpts().CPlusPlus) {
|
||||
if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name))
|
||||
Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()]
|
||||
.push_back(New);
|
||||
} else if (DeclContext *MergeDC = getPrimaryContextForMerging(Reader, DC)) {
|
||||
// Add the declaration to its redeclaration context so later merging
|
||||
// lookups will find it.
|
||||
@ -2727,7 +2732,8 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
|
||||
if (isSameEntity(Existing, D))
|
||||
return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
|
||||
TypedefNameForLinkage);
|
||||
} else if (DC->isTranslationUnit() && Reader.SemaObj) {
|
||||
} else if (DC->isTranslationUnit() && Reader.SemaObj &&
|
||||
!Reader.getContext().getLangOpts().CPlusPlus) {
|
||||
IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver;
|
||||
|
||||
// Temporarily consider the identifier to be up-to-date. We don't want to
|
||||
@ -2816,14 +2822,14 @@ Decl *ASTReader::getMostRecentExistingDecl(Decl *D) {
|
||||
template<typename DeclT>
|
||||
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
||||
Redeclarable<DeclT> *D,
|
||||
Decl *Previous) {
|
||||
Decl *Previous, Decl *Canon) {
|
||||
D->RedeclLink.setPrevious(cast<DeclT>(Previous));
|
||||
}
|
||||
namespace clang {
|
||||
template<>
|
||||
void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
||||
Redeclarable<FunctionDecl> *D,
|
||||
Decl *Previous) {
|
||||
Decl *Previous, Decl *Canon) {
|
||||
FunctionDecl *FD = static_cast<FunctionDecl*>(D);
|
||||
FunctionDecl *PrevFD = cast<FunctionDecl>(Previous);
|
||||
|
||||
@ -2850,25 +2856,17 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader,
|
||||
FD->IsInline = true;
|
||||
}
|
||||
|
||||
// If this declaration has an unresolved exception specification but the
|
||||
// previous declaration had a resolved one, resolve the exception
|
||||
// specification now. If this declaration has a resolved exception
|
||||
// specification but the previous declarations did not, apply our exception
|
||||
// specification to all prior ones now.
|
||||
// If we need to propagate an exception specification along the redecl
|
||||
// chain, make a note of that so that we can do so later.
|
||||
auto *FPT = FD->getType()->getAs<FunctionProtoType>();
|
||||
auto *PrevFPT = PrevFD->getType()->getAs<FunctionProtoType>();
|
||||
if (FPT && PrevFPT) {
|
||||
bool WasUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
|
||||
bool IsUnresolved = isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
|
||||
if (WasUnresolved && !IsUnresolved) {
|
||||
Reader.Context.adjustExceptionSpec(
|
||||
FD, PrevFPT->getExtProtoInfo().ExceptionSpec);
|
||||
} else if (!WasUnresolved && IsUnresolved) {
|
||||
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
|
||||
for (FunctionDecl *PrevFDToUpdate = PrevFD; PrevFDToUpdate;
|
||||
PrevFDToUpdate = PrevFDToUpdate->getPreviousDecl())
|
||||
Reader.Context.adjustExceptionSpec(PrevFDToUpdate, EPI.ExceptionSpec);
|
||||
}
|
||||
bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType());
|
||||
bool WasUnresolved =
|
||||
isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType());
|
||||
if (IsUnresolved != WasUnresolved)
|
||||
Reader.PendingExceptionSpecUpdates.insert(
|
||||
std::make_pair(Canon, IsUnresolved ? PrevFD : FD));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2877,14 +2875,14 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, ...) {
|
||||
}
|
||||
|
||||
void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
|
||||
Decl *Previous) {
|
||||
Decl *Previous, Decl *Canon) {
|
||||
assert(D && Previous);
|
||||
|
||||
switch (D->getKind()) {
|
||||
#define ABSTRACT_DECL(TYPE)
|
||||
#define DECL(TYPE, BASE) \
|
||||
case Decl::TYPE: \
|
||||
attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous); \
|
||||
#define DECL(TYPE, BASE) \
|
||||
case Decl::TYPE: \
|
||||
attachPreviousDeclImpl(Reader, cast<TYPE##Decl>(D), Previous, Canon); \
|
||||
break;
|
||||
#include "clang/AST/DeclNodes.inc"
|
||||
}
|
||||
@ -3388,7 +3386,7 @@ void ASTReader::loadPendingDeclChain(Decl *CanonDecl) {
|
||||
if (Chain[I] == CanonDecl)
|
||||
continue;
|
||||
|
||||
ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent);
|
||||
ASTDeclReader::attachPreviousDecl(*this, Chain[I], MostRecent, CanonDecl);
|
||||
MostRecent = Chain[I];
|
||||
}
|
||||
ASTDeclReader::attachLatestDecl(CanonDecl, MostRecent);
|
||||
@ -3732,23 +3730,24 @@ void ASTDeclReader::UpdateDecl(Decl *D, ModuleFile &ModuleFile,
|
||||
}
|
||||
|
||||
case UPD_CXX_RESOLVED_EXCEPTION_SPEC: {
|
||||
// FIXME: This doesn't send the right notifications if there are
|
||||
// ASTMutationListeners other than an ASTWriter.
|
||||
FunctionProtoType::ExceptionSpecInfo ESI;
|
||||
SmallVector<QualType, 8> ExceptionStorage;
|
||||
Reader.readExceptionSpec(ModuleFile, ExceptionStorage, ESI, Record, Idx);
|
||||
for (auto *Redecl : merged_redecls(D)) {
|
||||
auto *FD = cast<FunctionDecl>(Redecl);
|
||||
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
|
||||
if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
|
||||
// AST invariant: if any exception spec in the redecl chain is
|
||||
// resolved, all are resolved. We don't need to go any further.
|
||||
// FIXME: If the exception spec is resolved, check that it matches.
|
||||
break;
|
||||
}
|
||||
|
||||
// Update this declaration's exception specification, if needed.
|
||||
auto *FD = cast<FunctionDecl>(D);
|
||||
auto *FPT = FD->getType()->castAs<FunctionProtoType>();
|
||||
// FIXME: If the exception specification is already present, check that it
|
||||
// matches.
|
||||
if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) {
|
||||
FD->setType(Reader.Context.getFunctionType(
|
||||
FPT->getReturnType(), FPT->getParamTypes(),
|
||||
FPT->getExtProtoInfo().withExceptionSpec(ESI)));
|
||||
|
||||
// When we get to the end of deserializing, see if there are other decls
|
||||
// that we need to propagate this exception specification onto.
|
||||
Reader.PendingExceptionSpecUpdates.insert(
|
||||
std::make_pair(FD->getCanonicalDecl(), FD));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3731,7 +3731,9 @@ void ASTWriter::AddUpdatedDeclContext(const DeclContext *DC) {
|
||||
uint32_t
|
||||
ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
|
||||
llvm::SmallVectorImpl<char> &LookupTable) {
|
||||
assert(!DC->LookupPtr.getInt() && "must call buildLookups first");
|
||||
assert(!DC->HasLazyLocalLexicalLookups &&
|
||||
!DC->HasLazyExternalLexicalLookups &&
|
||||
"must call buildLookups first");
|
||||
|
||||
llvm::OnDiskChainedHashTableGenerator<ASTDeclContextNameLookupTrait>
|
||||
Generator;
|
||||
@ -5804,37 +5806,36 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD,
|
||||
}
|
||||
|
||||
void ASTWriter::ResolvedExceptionSpec(const FunctionDecl *FD) {
|
||||
assert(!WritingAST && "Already writing the AST!");
|
||||
FD = FD->getCanonicalDecl();
|
||||
if (!FD->isFromASTFile())
|
||||
return; // Not a function declared in PCH and defined outside.
|
||||
|
||||
DeclUpdates[FD].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
|
||||
assert(!DoneWritingDeclsAndTypes && "Already done writing updates!");
|
||||
if (!Chain) return;
|
||||
Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
|
||||
// If we don't already know the exception specification for this redecl
|
||||
// chain, add an update record for it.
|
||||
if (isUnresolvedExceptionSpec(cast<FunctionDecl>(D)
|
||||
->getType()
|
||||
->castAs<FunctionProtoType>()
|
||||
->getExceptionSpecType()))
|
||||
DeclUpdates[D].push_back(UPD_CXX_RESOLVED_EXCEPTION_SPEC);
|
||||
});
|
||||
}
|
||||
|
||||
void ASTWriter::DeducedReturnType(const FunctionDecl *FD, QualType ReturnType) {
|
||||
assert(!WritingAST && "Already writing the AST!");
|
||||
FD = FD->getCanonicalDecl();
|
||||
if (!FD->isFromASTFile())
|
||||
return; // Not a function declared in PCH and defined outside.
|
||||
|
||||
DeclUpdates[FD].push_back(DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
|
||||
if (!Chain) return;
|
||||
Chain->forEachFormerlyCanonicalImportedDecl(FD, [&](const Decl *D) {
|
||||
DeclUpdates[D].push_back(
|
||||
DeclUpdate(UPD_CXX_DEDUCED_RETURN_TYPE, ReturnType));
|
||||
});
|
||||
}
|
||||
|
||||
void ASTWriter::ResolvedOperatorDelete(const CXXDestructorDecl *DD,
|
||||
const FunctionDecl *Delete) {
|
||||
assert(!WritingAST && "Already writing the AST!");
|
||||
assert(Delete && "Not given an operator delete");
|
||||
for (auto *D : DD->redecls()) {
|
||||
if (D->isFromASTFile()) {
|
||||
// We added an operator delete that some imported destructor didn't
|
||||
// know about. Add an update record to let importers of us and that
|
||||
// declaration know about it.
|
||||
DeclUpdates[DD].push_back(
|
||||
DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!Chain) return;
|
||||
Chain->forEachFormerlyCanonicalImportedDecl(DD, [&](const Decl *D) {
|
||||
DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_RESOLVED_DTOR_DELETE, Delete));
|
||||
});
|
||||
}
|
||||
|
||||
void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) {
|
||||
@ -5851,8 +5852,7 @@ void ASTWriter::FunctionDefinitionInstantiated(const FunctionDecl *D) {
|
||||
if (!D->isFromASTFile())
|
||||
return;
|
||||
|
||||
DeclUpdates[D].push_back(
|
||||
DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
|
||||
DeclUpdates[D].push_back(DeclUpdate(UPD_CXX_ADDED_FUNCTION_DEFINITION));
|
||||
}
|
||||
|
||||
void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) {
|
||||
|
2
clang/test/Modules/Inputs/update-exception-spec/a.h
Normal file
2
clang/test/Modules/Inputs/update-exception-spec/a.h
Normal file
@ -0,0 +1,2 @@
|
||||
struct A { ~A() throw(int); };
|
||||
struct B { A a; };
|
3
clang/test/Modules/Inputs/update-exception-spec/b.h
Normal file
3
clang/test/Modules/Inputs/update-exception-spec/b.h
Normal file
@ -0,0 +1,3 @@
|
||||
struct A { ~A() throw(int); };
|
||||
struct B { A a; };
|
||||
inline void f(B *p) { p->~B(); }
|
3
clang/test/Modules/Inputs/update-exception-spec/c.h
Normal file
3
clang/test/Modules/Inputs/update-exception-spec/c.h
Normal file
@ -0,0 +1,3 @@
|
||||
#include "a.h"
|
||||
#include "b.h"
|
||||
inline void g(B *p) { p->~B(); }
|
@ -0,0 +1,3 @@
|
||||
module a { header "a.h" }
|
||||
module b { header "b.h" }
|
||||
module c { header "c.h" }
|
@ -1,7 +1,7 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups | FileCheck %s --check-prefix=CHECK-GLOBAL
|
||||
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump-lookups -ast-dump-filter N | FileCheck %s --check-prefix=CHECK-NAMESPACE-N
|
||||
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump | FileCheck %s --check-prefix=CHECK-DUMP
|
||||
// RUN: not %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -std=c++11 -ast-dump -ast-dump-filter SomeTemplate | FileCheck %s --check-prefix=CHECK-DUMP
|
||||
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11
|
||||
// RUN: %clang_cc1 -x objective-c++ -fmodules -fno-modules-error-recovery -fmodules-cache-path=%t -I %S/Inputs %s -verify -std=c++11 -DEARLY_IMPORT
|
||||
|
||||
@ -125,9 +125,10 @@ void g() {
|
||||
static_assert(Outer<int>::Inner<int>::f() == 1, "");
|
||||
static_assert(Outer<int>::Inner<int>::g() == 2, "");
|
||||
|
||||
#ifndef EARLY_IMPORT
|
||||
// FIXME: The textual inclusion above shouldn't cause this to fail!
|
||||
static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
|
||||
// FIXME: We're too lazy in merging class definitions to find the definition
|
||||
// of this function.
|
||||
static_assert(MergeTemplateDefinitions<int>::f() == 1, ""); // expected-error {{constant expression}} expected-note {{undefined}}
|
||||
// expected-note@cxx-templates-c.h:10 {{here}}
|
||||
static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
|
||||
|
||||
RedeclaredAsFriend<int> raf1;
|
||||
@ -140,7 +141,6 @@ MergeSpecializations<int[]>::partially_specialized_in_c spec_in_c_1;
|
||||
MergeSpecializations<char>::explicitly_specialized_in_a spec_in_a_2;
|
||||
MergeSpecializations<double>::explicitly_specialized_in_b spec_in_b_2;
|
||||
MergeSpecializations<bool>::explicitly_specialized_in_c spec_in_c_2;
|
||||
#endif
|
||||
|
||||
MergeAnonUnionMember<> maum_main;
|
||||
typedef DontWalkPreviousDeclAfterMerging<int> dwpdam_typedef_2;
|
||||
|
@ -11,6 +11,5 @@ static void g(int);
|
||||
// happen to find lookup results for 'g'; LookupResult::resolveKind needs to
|
||||
// be taught to prefer a visible result over a non-visible one.
|
||||
//
|
||||
// FIXME-error@-1 {{functions that differ only in their return type cannot be overloaded}}
|
||||
// FIXME-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}}
|
||||
// expected-no-diagnostics
|
||||
// expected-error@9 {{functions that differ only in their return type cannot be overloaded}}
|
||||
// expected-note@Inputs/linkage-merge-foo.h:2 {{previous declaration is here}}
|
||||
|
@ -15,9 +15,9 @@ bool b = F<int>{0} == F<int>{1};
|
||||
int x = f() + g();
|
||||
|
||||
// expected-note@a.h:5 {{definition has no member 'e2'}}
|
||||
// expected-note@a.h:3 {{declaration of 'f' does not match}}
|
||||
// expected-note@a.h:1 {{definition has no member 'm'}}
|
||||
// expected-note@b.h:3 {{declaration of 'f' does not match}}
|
||||
// expected-note@b.h:1 {{definition has no member 'n'}}
|
||||
|
||||
// expected-error@b.h:5 {{'E::e2' from module 'b' is not present in definition of 'E' in module 'a'}}
|
||||
// expected-error@b.h:3 {{'Y::f' from module 'b' is not present in definition of 'Y' in module 'a'}}
|
||||
// expected-error@b.h:2 {{'Y::m' from module 'b' is not present in definition of 'Y' in module 'a'}}
|
||||
// expected-error@a.h:3 {{'Y::f' from module 'a' is not present in definition of 'Y' in module 'b'}}
|
||||
// expected-error@a.h:2 {{'Y::n' from module 'a' is not present in definition of 'Y' in module 'b'}}
|
||||
|
@ -29,7 +29,7 @@ struct D {
|
||||
static constexpr int function(); // expected-note {{here}}
|
||||
};
|
||||
typedef D::A DB;
|
||||
constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{subexpression}} expected-note {{undefined}}
|
||||
constexpr int D_test(bool b) { return b ? D::variable : D::function(); } // expected-note {{undefined}}
|
||||
#endif
|
||||
|
||||
@import redecl_add_after_load;
|
||||
@ -54,6 +54,6 @@ constexpr int merged_struct_variable_test = D_test(true);
|
||||
constexpr int merged_struct_function_test = D_test(false);
|
||||
#ifndef IMPORT_DECLS
|
||||
// expected-error@-4 {{incomplete}}
|
||||
// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
|
||||
// @-4: definition of D::variable must be emitted, so it gets imported eagerly
|
||||
// expected-error@-4 {{constant}} expected-note@-4 {{in call to}}
|
||||
#endif
|
||||
|
6
clang/test/Modules/update-exception-spec.cpp
Normal file
6
clang/test/Modules/update-exception-spec.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
// RUN: rm -rf %t
|
||||
// RUN: %clang_cc1 -fexceptions -fcxx-exceptions -fmodules -fmodules-cache-path=%t -I%S/Inputs/update-exception-spec -emit-llvm-only %s
|
||||
#include "a.h"
|
||||
void use(B *p);
|
||||
#include "c.h"
|
||||
void use(B *p) { g(p); }
|
Loading…
x
Reference in New Issue
Block a user