using RecordData = ASTReader::RecordData;
- TypeID TypeIDForTypeDecl = 0;
+ TypeID DeferredTypeID = 0;
unsigned AnonymousDeclNumber;
GlobalDeclID NamedDeclForTagDecl = 0;
IdentifierInfo *TypedefNameForLinkage = nullptr;
void MergeDefinitionData(ObjCProtocolDecl *D,
struct ObjCProtocolDecl::DefinitionData &&NewDD);
+ static DeclContext *getPrimaryDCForAnonymousDecl(DeclContext *LexicalDC);
+
static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader,
DeclContext *DC,
unsigned Index);
if (auto *TD = dyn_cast<TypeDecl>(D)) {
// We have a fully initialized TypeDecl. Read its type now.
- TD->setTypeForDecl(Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull());
+ TD->setTypeForDecl(Reader.GetType(DeferredTypeID).getTypePtrOrNull());
// If this is a tag declaration with a typedef name for linkage, it's safe
// to load that typedef now.
cast<TypedefNameDecl>(Reader.GetDecl(NamedDeclForTagDecl));
} else if (auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
// if we have a fully initialized TypeDecl, we can safely read its type now.
- ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull();
+ ID->TypeForDecl = Reader.GetType(DeferredTypeID).getTypePtrOrNull();
} else if (auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (DeferredTypeID)
+ FD->setType(Reader.GetType(DeferredTypeID));
+
// FunctionDecl's body was written last after all other Stmts/Exprs.
// We only read it if FD doesn't already have a body (e.g., from another
// module).
VisitNamedDecl(TD);
TD->setLocStart(ReadSourceLocation());
// Delay type reading until after we have fully initialized the decl.
- TypeIDForTypeDecl = Record.getGlobalTypeID(Record.readInt());
+ DeferredTypeID = Record.getGlobalTypeID(Record.readInt());
}
ASTDeclReader::RedeclarableResult
void ASTDeclReader::VisitValueDecl(ValueDecl *VD) {
VisitNamedDecl(VD);
- VD->setType(Record.readType());
+ // For function declarations, defer reading the type in case the function has
+ // a deduced return type that references an entity declared within the
+ // function.
+ if (isa<FunctionDecl>(VD))
+ DeferredTypeID = Record.getGlobalTypeID(Record.readInt());
+ else
+ VD->setType(Record.readType());
}
void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) {
RedeclarableResult Redecl = VisitRedeclarable(FD);
VisitDeclaratorDecl(FD);
+ // Attach a type to this function. Use the real type if possible, but fall
+ // back to the type as written if it involves a deduced return type.
+ if (FD->getTypeSourceInfo() &&
+ FD->getTypeSourceInfo()->getType()->castAs<FunctionType>()
+ ->getReturnType()->getContainedAutoType()) {
+ // We'll set up the real type in Visit, once we've finished loading the
+ // function.
+ FD->setType(FD->getTypeSourceInfo()->getType());
+ } else {
+ FD->setType(Reader.GetType(DeferredTypeID));
+ DeferredTypeID = 0;
+ }
+
ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName());
FD->IdentifierNamespace = Record.readInt();
void ASTDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
RedeclarableResult Redecl = VisitRedeclarable(ID);
VisitObjCContainerDecl(ID);
- TypeIDForTypeDecl = Record.getGlobalTypeID(Record.readInt());
+ DeferredTypeID = Record.getGlobalTypeID(Record.readInt());
mergeRedeclarable(ID, Redecl);
ID->TypeParamList = ReadObjCTypeParamList();
//
// Beware: we do not yet know our canonical declaration, and may still
// get merged once the surrounding class template has got off the ground.
- TypeIDForTypeDecl = 0;
+ DeferredTypeID = 0;
}
break;
}
return true;
// Must be in the same context.
- if (!X->getDeclContext()->getRedeclContext()->Equals(
- Y->getDeclContext()->getRedeclContext()))
+ //
+ // Note that we can't use DeclContext::Equals here, because the DeclContexts
+ // could be two different declarations of the same function. (We will fix the
+ // semantic DC to refer to the primary definition after merging.)
+ if (!declaresSameEntity(cast<Decl>(X->getDeclContext()->getRedeclContext()),
+ cast<Decl>(Y->getDeclContext()->getRedeclContext())))
return false;
// Two typedefs refer to the same entity if they have the same underlying
}
ASTContext &C = FuncX->getASTContext();
- if (!C.hasSameType(FuncX->getType(), FuncY->getType())) {
+ auto GetTypeAsWritten = [](const FunctionDecl *FD) {
+ // Map to the first declaration that we've already merged into this one.
+ // The TSI of redeclarations might not match (due to calling conventions
+ // being inherited onto the type but not the TSI), but the TSI type of
+ // the first declaration of the function should match across modules.
+ FD = FD->getCanonicalDecl();
+ return FD->getTypeSourceInfo() ? FD->getTypeSourceInfo()->getType()
+ : FD->getType();
+ };
+ QualType XT = GetTypeAsWritten(FuncX), YT = GetTypeAsWritten(FuncY);
+ if (!C.hasSameType(XT, YT)) {
// We can get functions with different types on the redecl chain in C++17
// if they have differing exception specifications and at least one of
// the excpetion specs is unresolved.
- // FIXME: Do we need to check for C++14 deduced return types here too?
- auto *XFPT = FuncX->getType()->getAs<FunctionProtoType>();
- auto *YFPT = FuncY->getType()->getAs<FunctionProtoType>();
+ auto *XFPT = XT->getAs<FunctionProtoType>();
+ auto *YFPT = YT->getAs<FunctionProtoType>();
if (C.getLangOpts().CPlusPlus17 && XFPT && YFPT &&
(isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
- C.hasSameFunctionTypeIgnoringExceptionSpec(FuncX->getType(),
- FuncY->getType()))
+ C.hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
return true;
return false;
}
return nullptr;
}
+/// Find the declaration to use to populate the anonymous declaration table
+/// for the given lexical DeclContext. We only care about finding local
+/// definitions of the context; we'll merge imported ones as we go.
+DeclContext *
+ASTDeclReader::getPrimaryDCForAnonymousDecl(DeclContext *LexicalDC) {
+ // For classes, we track the definition as we merge.
+ if (auto *RD = dyn_cast<CXXRecordDecl>(LexicalDC)) {
+ auto *DD = RD->getCanonicalDecl()->DefinitionData;
+ return DD ? DD->Definition : nullptr;
+ }
+
+ // For anything else, walk its merged redeclarations looking for a definition.
+ // Note that we can't just call getDefinition here because the redeclaration
+ // chain isn't wired up.
+ for (auto *D : merged_redecls(cast<Decl>(LexicalDC))) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D))
+ if (FD->isThisDeclarationADefinition())
+ return FD;
+ if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
+ if (MD->isThisDeclarationADefinition())
+ return MD;
+ }
+
+ // No merged definition yet.
+ return nullptr;
+}
+
NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader,
DeclContext *DC,
unsigned Index) {
// If the lexical context has been merged, look into the now-canonical
// definition.
- if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
- DC = Merged;
+ auto *CanonDC = cast<Decl>(DC)->getCanonicalDecl();
// If we've seen this before, return the canonical declaration.
- auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[CanonDC];
if (Index < Previous.size() && Previous[Index])
return Previous[Index];
// If this is the first time, but we have parsed a declaration of the context,
// build the anonymous declaration list from the parsed declaration.
- if (!cast<Decl>(DC)->isFromASTFile()) {
- numberAnonymousDeclsWithin(DC, [&](NamedDecl *ND, unsigned Number) {
+ auto *PrimaryDC = getPrimaryDCForAnonymousDecl(DC);
+ if (PrimaryDC && !cast<Decl>(PrimaryDC)->isFromASTFile()) {
+ numberAnonymousDeclsWithin(PrimaryDC, [&](NamedDecl *ND, unsigned Number) {
if (Previous.size() == Number)
Previous.push_back(cast<NamedDecl>(ND->getCanonicalDecl()));
else
void ASTDeclReader::setAnonymousDeclForMerging(ASTReader &Reader,
DeclContext *DC, unsigned Index,
NamedDecl *D) {
- if (auto *Merged = Reader.MergedDeclContexts.lookup(DC))
- DC = Merged;
+ auto *CanonDC = cast<Decl>(DC)->getCanonicalDecl();
- auto &Previous = Reader.AnonymousDeclarationsForMerging[DC];
+ auto &Previous = Reader.AnonymousDeclarationsForMerging[CanonDC];
if (Index >= Previous.size())
Previous.resize(Index + 1);
if (!Previous[Index])
--- /dev/null
+// RUN: %clang_cc1 -fmodules -verify %s
+// expected-no-diagnostics
+
+#pragma clang module build A
+module A {}
+#pragma clang module contents
+#pragma clang module begin A
+template<typename T> auto f() { return []{}; }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build B
+module B {}
+#pragma clang module contents
+#pragma clang module begin B
+#pragma clang module import A
+inline auto x1() { return f<int>(); }
+inline auto z() { return []{}; }
+inline auto x2() { return z(); }
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module build C
+module C {}
+#pragma clang module contents
+#pragma clang module begin C
+#pragma clang module import A
+inline auto y1() { return f<int>(); }
+inline auto z() { return []{}; }
+inline auto y2() { return z(); }
+inline auto q() { return []{}; }
+inline auto y3() { return q(); }
+#pragma clang module end
+#pragma clang module endbuild
+
+inline auto q() { return []{}; }
+inline auto x3() { return q(); }
+
+#pragma clang module import B
+#pragma clang module import C
+using T = decltype(x1);
+using T = decltype(y1);
+
+using U = decltype(x2);
+using U = decltype(y2);
+
+using V = decltype(x3);
+using V = decltype(y3);