https://github.com/jcsxky updated https://github.com/llvm/llvm-project/pull/80288
>From 329e78b18bf83fe984cc1ff8830f5a8be8cf3f7b Mon Sep 17 00:00:00 2001 From: huqizhi <huqi...@feysh.com> Date: Thu, 1 Feb 2024 20:54:46 +0800 Subject: [PATCH] [Clang][Sema] fix outline member function template with default align crash --- clang/docs/ReleaseNotes.rst | 4 + clang/lib/Sema/SemaTemplateInstantiate.cpp | 14 +- clang/test/SemaTemplate/default-parm-init.cpp | 190 ++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaTemplate/default-parm-init.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 53040aa0f9074..8efdbf65abc19 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -188,6 +188,10 @@ Bug Fixes to C++ Support and (`#79745 <https://github.com/llvm/llvm-project/issues/79745>`_) - Fix incorrect code generation caused by the object argument of ``static operator()`` and ``static operator[]`` calls not being evaluated. Fixes (`#67976 <https://github.com/llvm/llvm-project/issues/67976>`_) +- Fix a crash when specializing an out-of-line member function with a default + parameter where we did an incorrect specialization of the initialization of + the default parameter. + Fixes (`#68490 <https://github.com/llvm/llvm-project/issues/68490>`_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 01b78e4424fb5..e5999fa50117e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3049,6 +3049,7 @@ bool Sema::SubstDefaultArgument( // default argument expression appears. ContextRAII SavedContext(*this, FD); std::unique_ptr<LocalInstantiationScope> LIS; + MultiLevelTemplateArgumentList NewTemplateArgs = TemplateArgs; if (ForCallExpr) { // When instantiating a default argument due to use in a call expression, @@ -3061,11 +3062,20 @@ bool Sema::SubstDefaultArgument( /*ForDefinition*/ false); if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs)) return true; + const FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); + if (PrimaryTemplate && PrimaryTemplate->isOutOfLine()) { + TemplateArgumentList *CurrentTemplateArgumentList = + TemplateArgumentList::CreateCopy(getASTContext(), + TemplateArgs.getInnermost()); + NewTemplateArgs = getTemplateInstantiationArgs( + FD, FD->getDeclContext(), /*Final=*/false, + CurrentTemplateArgumentList->asArray(), /*RelativeToPrimary=*/true); + } } runWithSufficientStackSpace(Loc, [&] { - Result = SubstInitializer(PatternExpr, TemplateArgs, - /*DirectInit*/false); + Result = SubstInitializer(PatternExpr, NewTemplateArgs, + /*DirectInit*/ false); }); } if (Result.isInvalid()) diff --git a/clang/test/SemaTemplate/default-parm-init.cpp b/clang/test/SemaTemplate/default-parm-init.cpp new file mode 100644 index 0000000000000..73ba8998df6a9 --- /dev/null +++ b/clang/test/SemaTemplate/default-parm-init.cpp @@ -0,0 +1,190 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s +// expected-no-diagnostics + +namespace std { + +template<typename Signature> class function; + +template<typename R, typename... Args> class invoker_base { +public: + virtual ~invoker_base() { } + virtual R invoke(Args...) = 0; + virtual invoker_base* clone() = 0; +}; + +template<typename F, typename R, typename... Args> +class functor_invoker : public invoker_base<R, Args...> { +public: + explicit functor_invoker(const F& f) : f(f) { } + R invoke(Args... args) { return f(args...); } + functor_invoker* clone() { return new functor_invoker(f); } + +private: + F f; +}; + +template<typename R, typename... Args> +class function<R (Args...)> { +public: + typedef R result_type; + function() : invoker (0) { } + function(const function& other) : invoker(0) { + if (other.invoker) + invoker = other.invoker->clone(); + } + + template<typename F> function(const F& f) : invoker(0) { + invoker = new functor_invoker<F, R, Args...>(f); + } + + ~function() { + if (invoker) + delete invoker; + } + + function& operator=(const function& other) { + function(other).swap(*this); + return *this; + } + + template<typename F> + function& operator=(const F& f) { + function(f).swap(*this); + return *this; + } + + void swap(function& other) { + invoker_base<R, Args...>* tmp = invoker; + invoker = other.invoker; + other.invoker = tmp; + } + + result_type operator()(Args... args) const { + return invoker->invoke(args...); + } + +private: + invoker_base<R, Args...>* invoker; +}; + +} + +template<typename TemplateParam> +struct Problem { + template<typename FunctionTemplateParam> + constexpr int FuncAlign(int param = alignof(FunctionTemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncSizeof(int param = sizeof(FunctionTemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncAlign2(int param = alignof(TemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncSizeof2(int param = sizeof(TemplateParam)); +}; + +template<typename TemplateParam> +struct Problem<TemplateParam*> { + template<typename FunctionTemplateParam> + constexpr int FuncAlign(int param = alignof(FunctionTemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncSizeof(int param = sizeof(FunctionTemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncAlign2(int param = alignof(TemplateParam)); + + template<typename FunctionTemplateParam> + constexpr int FuncSizeof2(int param = sizeof(TemplateParam)); +}; + +template<typename TemplateParam> +template<typename FunctionTemplateParam> +constexpr int Problem<TemplateParam*>::FuncAlign(int param) { + return 2U*param; +} + +template<typename TemplateParam> +template<typename FunctionTemplateParam> +constexpr int Problem<TemplateParam*>::FuncSizeof(int param) { + return 2U*param; +} + +template<typename TemplateParam> +template<typename FunctionTemplateParam> +constexpr int Problem<TemplateParam*>::FuncAlign2(int param) { + return 2U*param; +} + +template<typename TemplateParam> +template<typename FunctionTemplateParam> +constexpr int Problem<TemplateParam*>::FuncSizeof2(int param) { + return 2U*param; +} + +template <> +template<typename FunctionTemplateParam> +constexpr int Problem<int>::FuncAlign(int param) { + return param; +} + +template <> +template<typename FunctionTemplateParam> +constexpr int Problem<int>::FuncSizeof(int param) { + return param; +} + +template <> +template<typename FunctionTemplateParam> +constexpr int Problem<int>::FuncAlign2(int param) { + return param; +} + +template <> +template<typename FunctionTemplateParam> +constexpr int Problem<int>::FuncSizeof2(int param) { + return param; +} + +void foo() { + Problem<int> p = {}; + static_assert(p.FuncAlign<char>() == alignof(char)); + static_assert(p.FuncSizeof<char>() == sizeof(char)); + static_assert(p.FuncAlign2<char>() == alignof(int)); + static_assert(p.FuncSizeof2<char>() == sizeof(int)); + Problem<short*> q = {}; + static_assert(q.FuncAlign<char>() == 2U * alignof(char)); + static_assert(q.FuncSizeof<char>() == 2U * sizeof(char)); + static_assert(q.FuncAlign2<char>() == 2U *alignof(short)); + static_assert(q.FuncSizeof2<char>() == 2U * sizeof(short)); +} + +template <typename T> +class A { + public: + void run( + std::function<void(T&)> f1 = [](auto&&) {}, + std::function<void(T&)> f2 = [](auto&&) {}); + private: + class Helper { + public: + explicit Helper(std::function<void(T&)> f2) : f2_(f2) {} + std::function<void(T&)> f2_; + }; +}; + +template <typename T> +void A<T>::run(std::function<void(T&)> f1, + std::function<void(T&)> f2) { + Helper h(f2); +} + +struct B {}; + +int main() { + A<B> a; + a.run([&](auto& l) {}); + return 0; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits