...before checking that the default argument is valid with
CheckDefaultArgumentVisitor.
Currently the restrictions on a default argument are checked with the visitor
CheckDefaultArgumentVisitor in ActOnParamDefaultArgument before
performing the conversion to the parameter type in SetParamDefaultArgument.
This was fine before the previous patch but now some valid code post-CWG 2346
is rejected:
void test() {
const int i2 = 0;
extern void h2a(int x = i2); // FIXME: ok, not odr-use
extern void h2b(int x = i2 + 0); // ok, not odr-use
}
This is because the reference to i2 in h2a has not been marked yet with
NOUR_Constant. i2 is marked NOUR_Constant when the conversion to the parameter
type is done, which is done just after.
The solution is to do the conversion to the parameter type before checking
the restrictions on default arguments with CheckDefaultArgumentVisitor.
This has the side-benefit of improving some diagnostics.
Differential Revision: https://reviews.llvm.org/D81616
Reviewed By: rsmith
40 lines
1.4 KiB
C++
40 lines
1.4 KiB
C++
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
|
|
|
|
template <class> auto fn0 = [] {};
|
|
template <typename> void foo0() { fn0<char>(); }
|
|
|
|
template<typename T> auto fn1 = [](auto a) { return a + T(1); };
|
|
template<typename T> auto v1 = [](int a = T()) { return a; }();
|
|
// expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
|
|
// expected-note@-2{{passing argument to parameter 'a' here}}
|
|
|
|
struct S {
|
|
template<class T>
|
|
static constexpr T t = [](int f = T(7)){return f;}(); // expected-error{{constexpr variable 't<int>' must be initialized by a constant expression}} expected-note{{cannot be used in a constant expression}}
|
|
};
|
|
|
|
template <typename X>
|
|
int foo2() {
|
|
X a = 0x61;
|
|
fn1<char>(a);
|
|
(void)v1<int>;
|
|
(void)v1<int *>; // expected-note{{in instantiation of variable template specialization 'v1' requested here}}
|
|
(void)S::t<int>; // expected-note{{in instantiation of static data member 'S::t<int>' requested here}}
|
|
return 0;
|
|
}
|
|
|
|
template<class C>
|
|
int foo3() {
|
|
C::m1(); // expected-error{{type 'long long' cannot be used prior to '::' because it has no members}}
|
|
return 1;
|
|
}
|
|
|
|
template<class C>
|
|
auto v2 = [](int a = foo3<C>()){}; // expected-note{{in instantiation of function template specialization 'foo3<long long>' requested here}}
|
|
|
|
int main() {
|
|
v2<long long>(); // This line causes foo3<long long> to be instantiated.
|
|
v2<long long>(2); // This line does not.
|
|
foo2<int>();
|
|
}
|