diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 0eecb6f5d65a..b959f596f902 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -539,6 +539,11 @@ private: /// declaration that has an exception specification. llvm::SmallMapVector PendingExceptionSpecUpdates; + /// Deduced return type updates that have been loaded but not yet propagated + /// across the relevant redeclaration chain. The map key is the canonical + /// declaration and the value is the deduced return type. + llvm::SmallMapVector PendingDeducedTypeUpdates; + /// Declarations that have been imported and have typedef names for /// linkage purposes. llvm::DenseMap, NamedDecl *> @@ -1056,6 +1061,12 @@ private: /// Objective-C protocols. std::deque PotentiallyInterestingDecls; + /// The list of deduced function types that we have not yet read, because + /// they might contain a deduced return type that refers to a local type + /// declared within the function. + SmallVector, 16> + PendingFunctionTypes; + /// The list of redeclaration chains that still need to be /// reconstructed, and the local offset to the corresponding list /// of redeclarations. diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 723839ff62bf..8a02ea93f401 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -9254,7 +9254,7 @@ std::string ASTReader::getOwningModuleNameForDiagnostic(const Decl *D) { } void ASTReader::finishPendingActions() { - while (!PendingIdentifierInfos.empty() || + while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() || !PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() || !PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() || !PendingUpdateRecords.empty()) { @@ -9273,6 +9273,21 @@ void ASTReader::finishPendingActions() { SetGloballyVisibleDecls(II, DeclIDs, &TopLevelDecls[II]); } + // Load each function type that we deferred loading because it was a + // deduced type that might refer to a local type declared within itself. + for (unsigned I = 0; I != PendingFunctionTypes.size(); ++I) { + auto *FD = PendingFunctionTypes[I].first; + FD->setType(GetType(PendingFunctionTypes[I].second)); + + // If we gave a function a deduced return type, remember that we need to + // propagate that along the redeclaration chain. + auto *DT = FD->getReturnType()->getContainedDeducedType(); + if (DT && DT->isDeduced()) + PendingDeducedTypeUpdates.insert( + {FD->getCanonicalDecl(), FD->getReturnType()}); + } + PendingFunctionTypes.clear(); + // For each decl chain that we wanted to complete while deserializing, mark // it as "still needs to be completed". for (unsigned I = 0; I != PendingIncompleteDeclChains.size(); ++I) { @@ -9282,7 +9297,8 @@ void ASTReader::finishPendingActions() { // Load pending declaration chains. for (unsigned I = 0; I != PendingDeclChains.size(); ++I) - loadPendingDeclChain(PendingDeclChains[I].first, PendingDeclChains[I].second); + loadPendingDeclChain(PendingDeclChains[I].first, + PendingDeclChains[I].second); PendingDeclChains.clear(); // Make the most recent of the top-level declarations visible. @@ -11531,11 +11547,16 @@ void ASTReader::FinishedDeserializing() { --NumCurrentElementsDeserializing; if (NumCurrentElementsDeserializing == 0) { - // Propagate exception specification updates along redeclaration chains. - while (!PendingExceptionSpecUpdates.empty()) { - auto Updates = std::move(PendingExceptionSpecUpdates); + // Propagate exception specification and deduced type updates along + // redeclaration chains. + // + // We do this now rather than in finishPendingActions because we want to + // be able to walk the complete redeclaration chains of the updated decls. + while (!PendingExceptionSpecUpdates.empty() || + !PendingDeducedTypeUpdates.empty()) { + auto ESUpdates = std::move(PendingExceptionSpecUpdates); PendingExceptionSpecUpdates.clear(); - for (auto Update : Updates) { + for (auto Update : ESUpdates) { ProcessingUpdatesRAIIObj ProcessingUpdates(*this); auto *FPT = Update.second->getType()->castAs(); auto ESI = FPT->getExtProtoInfo().ExceptionSpec; @@ -11544,6 +11565,15 @@ void ASTReader::FinishedDeserializing() { for (auto *Redecl : Update.second->redecls()) getContext().adjustExceptionSpec(cast(Redecl), ESI); } + + auto DTUpdates = std::move(PendingDeducedTypeUpdates); + PendingDeducedTypeUpdates.clear(); + for (auto Update : DTUpdates) { + ProcessingUpdatesRAIIObj ProcessingUpdates(*this); + // FIXME: If the return type is already deduced, check that it matches. + getContext().adjustDeducedFunctionResultType(Update.first, + Update.second); + } } if (ReadTimer) diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index d17ec8e04618..613579d90793 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -541,9 +541,6 @@ void ASTDeclReader::Visit(Decl *D) { // if we have a fully initialized TypeDecl, we can safely read its type now. ID->TypeForDecl = Reader.GetType(DeferredTypeID).getTypePtrOrNull(); } else if (auto *FD = dyn_cast(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). @@ -844,10 +841,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { // We'll set up the real type in Visit, once we've finished loading the // function. FD->setType(FD->getTypeSourceInfo()->getType()); + Reader.PendingFunctionTypes.push_back({FD, DeferredTypeID}); } else { FD->setType(Reader.GetType(DeferredTypeID)); - DeferredTypeID = 0; } + DeferredTypeID = 0; ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName()); FD->IdentifierNamespace = Record.readInt(); @@ -3370,6 +3368,11 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, } } +static bool isUndeducedReturnType(QualType T) { + auto *DT = T->getContainedDeducedType(); + return DT && !DT->isDeduced(); +} + template<> void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, Redeclarable *D, @@ -3401,17 +3404,26 @@ void ASTDeclReader::attachPreviousDeclImpl(ASTReader &Reader, FD->setImplicitlyInline(true); } - // 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(); auto *PrevFPT = PrevFD->getType()->getAs(); if (FPT && PrevFPT) { + // If we need to propagate an exception specification along the redecl + // chain, make a note of that so that we can do so later. bool IsUnresolved = isUnresolvedExceptionSpec(FPT->getExceptionSpecType()); bool WasUnresolved = isUnresolvedExceptionSpec(PrevFPT->getExceptionSpecType()); if (IsUnresolved != WasUnresolved) Reader.PendingExceptionSpecUpdates.insert( - std::make_pair(Canon, IsUnresolved ? PrevFD : FD)); + {Canon, IsUnresolved ? PrevFD : FD}); + + // If we need to propagate a deduced return type along the redecl chain, + // make a note of that so that we can do it later. + bool IsUndeduced = isUndeducedReturnType(FPT->getReturnType()); + bool WasUndeduced = isUndeducedReturnType(PrevFPT->getReturnType()); + if (IsUndeduced != WasUndeduced) + Reader.PendingDeducedTypeUpdates.insert( + {cast(Canon), + (IsUndeduced ? PrevFPT : FPT)->getReturnType()}); } } @@ -4328,14 +4340,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, } case UPD_CXX_DEDUCED_RETURN_TYPE: { - // FIXME: Also do this when merging redecls. + auto *FD = cast(D); QualType DeducedResultType = Record.readType(); - for (auto *Redecl : merged_redecls(D)) { - // FIXME: If the return type is already deduced, check that it matches. - auto *FD = cast(Redecl); - Reader.getContext().adjustDeducedFunctionResultType(FD, - DeducedResultType); - } + Reader.PendingDeducedTypeUpdates.insert( + {FD->getCanonicalDecl(), DeducedResultType}); break; } diff --git a/clang/test/Modules/merge-deduced-return.cpp b/clang/test/Modules/merge-deduced-return.cpp index 0a4de7b97554..71dc29b633b6 100644 --- a/clang/test/Modules/merge-deduced-return.cpp +++ b/clang/test/Modules/merge-deduced-return.cpp @@ -8,6 +8,8 @@ module A {} #pragma clang module begin A inline auto f() { struct X {}; return X(); } inline auto a = f(); +auto g(int); +template auto h(T t) { return g(t); } #pragma clang module end #pragma clang module endbuild @@ -17,12 +19,14 @@ module B {} #pragma clang module begin B inline auto f() { struct X {}; return X(); } inline auto b = f(); +auto g(int) { return 0; } #pragma clang module end #pragma clang module endbuild #ifdef LOCAL inline auto f() { struct X {}; return X(); } inline auto b = f(); +auto g(int) { return 0; } #else #pragma clang module import B #endif @@ -31,3 +35,5 @@ inline auto b = f(); using T = decltype(a); using T = decltype(b); + +int test_g = h(0); diff --git a/clang/test/Modules/merge-lambdas.cpp b/clang/test/Modules/merge-lambdas.cpp index 8b3b5013284b..463a4c9b2fc6 100644 --- a/clang/test/Modules/merge-lambdas.cpp +++ b/clang/test/Modules/merge-lambdas.cpp @@ -46,3 +46,6 @@ using U = decltype(y2); using V = decltype(x3); using V = decltype(y3); + +#pragma clang module import A +void (*p)() = f();