diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 93eecbe0e1363..01c4ee97662b6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1049,6 +1049,11 @@ Bug Fixes to C++ Support - Set the ``__cpp_auto_cast`` feature test macro in C++23 mode. +- Fix crash for inconsistent deducing state of function return types + in importing modules. + Fixes (`#78830 `_) + Fixes (`#60085 `_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 21d791f5cd89a..dd1451bbf2d2c 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -550,6 +550,10 @@ class ASTReader /// declaration and the value is the deduced return type. llvm::SmallMapVector PendingDeducedTypeUpdates; + /// Functions has undededuced return type and we wish we can find the deduced + /// return type by iterating the redecls in other modules. + llvm::SmallVector PendingUndeducedFunctionDecls; + /// Declarations that have been imported and have typedef names for /// linkage purposes. llvm::DenseMap, NamedDecl *> diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index fe8782a3eb9e7..fecd94e875f67 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -9534,12 +9534,21 @@ void ASTReader::finishPendingActions() { auto *FD = PendingDeducedFunctionTypes[I].first; FD->setType(GetType(PendingDeducedFunctionTypes[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()}); + if (auto *DT = FD->getReturnType()->getContainedDeducedType()) { + // If we gave a function a deduced return type, remember that we need to + // propagate that along the redeclaration chain. + if (DT->isDeduced()) { + PendingDeducedTypeUpdates.insert( + {FD->getCanonicalDecl(), FD->getReturnType()}); + continue; + } + + // The function has undeduced DeduceType return type. We hope we can + // find the deduced type by iterating the redecls in other modules + // later. + PendingUndeducedFunctionDecls.push_back(FD); + continue; + } } PendingDeducedFunctionTypes.clear(); @@ -10105,6 +10114,13 @@ void ASTReader::FinishedDeserializing() { getContext().adjustDeducedFunctionResultType(Update.first, Update.second); } + + auto UDTUpdates = std::move(PendingUndeducedFunctionDecls); + PendingUndeducedFunctionDecls.clear(); + // We hope we can find the deduced type for the functions by iterating + // redeclarations in other modules. + for (FunctionDecl *UndeducedFD : UDTUpdates) + (void)UndeducedFD->getMostRecentDecl(); } if (ReadTimer) diff --git a/clang/test/Modules/pr60085.cppm b/clang/test/Modules/pr60085.cppm new file mode 100644 index 0000000000000..fd6fd914a543c --- /dev/null +++ b/clang/test/Modules/pr60085.cppm @@ -0,0 +1,85 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/d.cppm \ +// RUN: -emit-module-interface -o %t/d.pcm +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/c.cppm \ +// RUN: -emit-module-interface -o %t/c.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/b.cppm \ +// RUN: -emit-module-interface -o %t/b.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/a.cppm \ +// RUN: -emit-module-interface -o %t/a.pcm -fprebuilt-module-path=%t +// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple %t/a.pcm \ +// RUN: -S -emit-llvm -disable-llvm-passes -o - -fprebuilt-module-path=%t \ +// RUN: | FileCheck %t/a.cppm + +//--- d.cppm +export module d; + +export template +struct integer { + using type = int; + + static constexpr auto value() { + return 0; + } + + friend constexpr void f(integer const x) { + x.value(); + } +}; + +export constexpr void ddd(auto const value) { + f(value); +} + + +template +constexpr auto dd = T(); + +export template +constexpr auto d() { + dd; +} + +//--- c.cppm +export module c; + +import d; + +template +auto cc = T(); + +auto c() { + cc>; + integer().value(); +} + +//--- b.cppm +export module b; + +import d; + +auto b() { + integer::type; +} + +//--- a.cppm +export module a; + +import b; +import c; +import d; + +constexpr void aa() { + d>(); + ddd(integer()); +} + +export extern "C" void a() { + aa(); +} + +// Checks that we emit the IR successfully. +// CHECK: define{{.*}}@a( diff --git a/clang/test/Modules/pr78830.cppm b/clang/test/Modules/pr78830.cppm new file mode 100644 index 0000000000000..a3b1a8021ebea --- /dev/null +++ b/clang/test/Modules/pr78830.cppm @@ -0,0 +1,56 @@ +// RUN: rm -rf %t +// RUN: mkdir -p %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/Type.cppm -emit-module-interface -o \ +// RUN: %t/MyVec-Type.pcm -triple=x86_64-linux-gnu +// RUN:%clang_cc1 -std=c++20 %t/Vec.cppm -emit-module-interface -o \ +// RUN: %t/MyVec-Vec.pcm -fmodule-file=MyVec:Type=%t/MyVec-Type.pcm \ +// RUN: -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++20 %t/Vec2.cppm -emit-module-interface -o \ +// RUN: %t/MyVec-Vec2.pcm -fmodule-file=MyVec:Type=%t/MyVec-Type.pcm \ +// RUN: -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++20 %t/Calculator.cppm -emit-module-interface -o \ +// RUN: %t/MyVec-Calculator.pcm -fmodule-file=MyVec:Vec=%t/MyVec-Vec.pcm \ +// RUN: -fmodule-file=MyVec:Vec2=%t/MyVec-Vec2.pcm \ +// RUN: -fmodule-file=MyVec:Type=%t/MyVec-Type.pcm \ +// RUN: -triple=x86_64-linux-gnu +// RUN: %clang_cc1 -std=c++20 %t/MyVec-Calculator.pcm -S -emit-llvm \ +// RUN: -fmodule-file=MyVec:Vec=%t/MyVec-Vec.pcm \ +// RUN: -fmodule-file=MyVec:Vec2=%t/MyVec-Vec2.pcm \ +// RUN: -fmodule-file=MyVec:Type=%t/MyVec-Type.pcm \ +// RUN: -triple=x86_64-linux-gnu -o - \ +// RUN: | FileCheck %t/Calculator.cppm + +//--- Type.cppm +export module MyVec:Type; + +template struct Size { + auto total() const { return 1; } +}; + +//--- Vec.cppm +export module MyVec:Vec; +import :Type; + +int size_ = Size().total(); + +//--- Vec2.cppm +export module MyVec:Vec2; +import :Type; + +struct Vec2 { + Size size_; +}; + +//--- Calculator.cppm +export module MyVec:Calculator; + +import :Vec; +import :Vec2; + +auto Calculate() { return Size().total(); }; + +// Check the emitted module initializer to make sure we generate the module unit +// successfully. +// CHECK: @_ZW5MyVec9Calculatev