Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -3054,7 +3054,9 @@ /// Implicit declartion of a temporary that was materialized by /// MaterializeTemporaryExpr -class LifetimeExtendedTemporaryDecl final : public Decl { +class LifetimeExtendedTemporaryDecl final + : public Decl, + public Mergeable { friend class MaterializeTemporaryExpr; friend class ASTDeclReader; Index: clang/include/clang/AST/TextNodeDumper.h =================================================================== --- clang/include/clang/AST/TextNodeDumper.h +++ clang/include/clang/AST/TextNodeDumper.h @@ -346,6 +346,8 @@ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); void VisitBlockDecl(const BlockDecl *D); void VisitConceptDecl(const ConceptDecl *D); + void + VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D); }; } // namespace clang Index: clang/include/clang/Serialization/ASTReader.h =================================================================== --- clang/include/clang/Serialization/ASTReader.h +++ clang/include/clang/Serialization/ASTReader.h @@ -551,6 +551,14 @@ llvm::DenseMap> AnonymousDeclarationsForMerging; + /// Key used to identify LifetimeExtendedTemporaryDecl for merging. + /// containg the lifetime-extending declaration and the mangling number. + using LETemporaryKey = std::pair; + + /// Map of already deserialiazed temporaries. + llvm::DenseMap + LETemporaryForMerging; + struct FileDeclsInfo { ModuleFile *Mod = nullptr; ArrayRef Decls; Index: clang/lib/AST/TextNodeDumper.cpp =================================================================== --- clang/lib/AST/TextNodeDumper.cpp +++ clang/lib/AST/TextNodeDumper.cpp @@ -1338,6 +1338,18 @@ OS << " <<getNumParams() << ">>>"; } +void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D) { + OS << " extended by "; + dumpBareDeclRef(D->getExtendingDecl()); + OS << " mangling "; + { + ColorScope Color(OS, ShowColors, ValueColor); + OS << D->getManglingNumber(); + } + OS << " subexpr"; + dumpPointer(D); +} + void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) { dumpName(D); dumpType(D->getType()); Index: clang/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- clang/lib/Serialization/ASTReaderDecl.cpp +++ clang/lib/Serialization/ASTReaderDecl.cpp @@ -2355,6 +2355,7 @@ if (Record.readInt()) D->Value = new (D->getASTContext()) APValue(Record.readAPValue()); D->ManglingNumber = Record.readInt(); + mergeMergeable(D); } std::pair @@ -2562,17 +2563,32 @@ if (!Reader.getContext().getLangOpts().Modules) return; + Decl* RealDecl = static_cast(D); + // ODR-based merging is performed in C++ and in some cases (tag types) in C. // Note that C identically-named things in different translation units are // not redeclarations, but may still have compatible types, where ODR-like // semantics may apply. if (!Reader.getContext().getLangOpts().CPlusPlus && - !allowODRLikeMergeInC(dyn_cast(static_cast(D)))) + !allowODRLikeMergeInC(dyn_cast(RealDecl))) + return; + + if (auto *LETDecl = dyn_cast(RealDecl)) { + LETDecl->dump(); + auto LookupResult = + Reader.LETemporaryForMerging.FindAndConstruct(std::make_pair( + LETDecl->getExtendingDecl(), LETDecl->getManglingNumber())); + if (LookupResult.getSecond()) + Reader.getContext().setPrimaryMergedDecl( + LETDecl, LookupResult.getSecond()->getCanonicalDecl()); + else + LookupResult.getSecond() = LETDecl; return; + } - if (FindExistingResult ExistingRes = findExisting(static_cast(D))) + if (FindExistingResult ExistingRes = findExisting(cast(RealDecl))) if (T *Existing = ExistingRes) - Reader.getContext().setPrimaryMergedDecl(static_cast(D), + Reader.getContext().setPrimaryMergedDecl(RealDecl, Existing->getCanonicalDecl()); } Index: clang/test/Modules/Inputs/merge-lifetime-extended-temporary/a.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/merge-lifetime-extended-temporary/a.h @@ -0,0 +1,2 @@ + +constexpr const int& LETemp = 0; Index: clang/test/Modules/Inputs/merge-lifetime-extended-temporary/b.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/merge-lifetime-extended-temporary/b.h @@ -0,0 +1,4 @@ + +#include "a.h" + +constexpr const int* PtrTemp1 = &LETemp; \ No newline at end of file Index: clang/test/Modules/Inputs/merge-lifetime-extended-temporary/c.h =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/merge-lifetime-extended-temporary/c.h @@ -0,0 +1,4 @@ + +#include "a.h" + +constexpr const int* PtrTemp2 = &LETemp; \ No newline at end of file Index: clang/test/Modules/Inputs/merge-lifetime-extended-temporary/module.modulemap =================================================================== --- /dev/null +++ clang/test/Modules/Inputs/merge-lifetime-extended-temporary/module.modulemap @@ -0,0 +1,14 @@ +module "a" { + export * + header "a.h" +} + +module "b" { + export * + header "b.h" +} + +module "c" { + export * + header "c.h" +} \ No newline at end of file Index: clang/test/Modules/merge-lifetime-extended-temporary.cpp =================================================================== --- /dev/null +++ clang/test/Modules/merge-lifetime-extended-temporary.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-lifetime-extended-temporary -verify -std=c++11 %s -DORDER=1 +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -x c++ -I%S/Inputs/merge-lifetime-extended-temporary -verify -std=c++11 %s -DORDER=2 + +// expected-no-diagnostics +#if ORDER == 1 +#include "c.h" +#include "b.h" +#else +#include "b.h" +#include "c.h" +#endif + +static_assert(PtrTemp1 == &LETemp, ""); +static_assert(PtrTemp1 == PtrTemp2, "");