llvm-project/clang/test/SemaTemplate/default-parm-init.cpp
Qizhi Hu 752c172bc7
[Clang][Sema] fix outline member function template with default align crash (#80288)
Try to fix [issue](https://github.com/llvm/llvm-project/issues/68490 )
and some extented problem. Root cause of current issue is that error
handling in instantiation of function parameter with default
initialization on sizeof or align expression. When instance an
out-of-line template member function, depth of `TemplateTypeParmDecl` in
default initialization doesn't change while depth of other template
parameter does and this will lead to some template parameter
uninstanced. Also, sometime it will leader to wrong instantiation when
it uses the template parameter of the template class.
Fix it by add template args of context. This will make
MultiLevelTemplateArgumentList::getNumLevels matching the depth of
template parameter. Testcase with some static_assert demonstrates the
template parameter has been instanced correctly.
But, the default initialization of lambda expression compiles failed
when only checking if the member function is out-of-line. We should
check the `PrimaryFunctionTemplateDecl` of the funtion if it's
out-of-line.

Co-authored-by: huqizhi <836744285@qq.com>
2024-02-03 21:49:09 +08:00

191 lines
4.7 KiB
C++

// 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;
}