info.in_decl = t;
gcc_assert (TREE_CODE (t) == TEMPLATE_DECL);
+
+ args = add_outermost_template_args (t, args);
+
+ tree result = boolean_true_node;
if (tree norm = normalize_template_requirements (t, info.noisy ()))
{
+ if (!push_tinst_level (t, args))
+ return result;
tree pattern = DECL_TEMPLATE_RESULT (t);
push_access_scope (pattern);
- tree result = satisfy_associated_constraints (norm, args, info);
+ result = satisfy_associated_constraints (norm, args, info);
pop_access_scope (pattern);
- return result;
+ pop_tinst_level ();
}
- return boolean_true_node;
+ return result;
}
static tree
extern tree tparm_object_argument (tree);
extern bool explicit_class_specialization_p (tree);
extern bool push_tinst_level (tree);
+extern bool push_tinst_level (tree, tree);
extern bool push_tinst_level_loc (tree, location_t);
+extern bool push_tinst_level_loc (tree, tree, location_t);
extern void pop_tinst_level (void);
extern struct tinst_level *outermost_tinst_level(void);
extern void init_template_processing (void);
(EXTRA_ARGS) levels are added. This function is used to combine
the template arguments from a partial instantiation with the
template arguments used to attain the full instantiation from the
- partial instantiation. */
+ partial instantiation.
+
+ If ARGS is a TEMPLATE_DECL, use its parameters as args. */
tree
add_outermost_template_args (tree args, tree extra_args)
{
tree new_args;
+ if (!args)
+ return extra_args;
+ if (TREE_CODE (args) == TEMPLATE_DECL)
+ {
+ tree ti = get_template_info (DECL_TEMPLATE_RESULT (args));
+ args = TI_ARGS (ti);
+ }
+
/* If there are more levels of EXTRA_ARGS than there are ARGS,
something very fishy is going on. */
gcc_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args));
/* We're starting to instantiate D; record the template instantiation context
at LOC for diagnostics and to restore it later. */
-static bool
+bool
push_tinst_level_loc (tree tldcl, tree targs, location_t loc)
{
struct tinst_level *new_level;
/* We're starting substitution of TMPL<ARGS>; record the template
substitution context for diagnostics and to restore it later. */
-static bool
+bool
push_tinst_level (tree tmpl, tree args)
{
return push_tinst_level_loc (tmpl, args, input_location);
goto fail;
}
+ deduced:
+
+ /* CWG2369: Check satisfaction before non-deducible conversions. */
+ if (!constraints_satisfied_p (fn, targs))
+ {
+ if (explain_p)
+ diagnose_constraints (DECL_SOURCE_LOCATION (fn), fn, targs);
+ goto fail;
+ }
+
/* DR 1391: All parameters have args, now check non-dependent parms for
- convertibility. */
- if (check_non_deducible_conversions (parms, args, nargs, fn, strict, flags,
- convs, explain_p))
+ convertibility. We don't do this if all args were explicitly specified,
+ as the standard says that we substitute explicit args immediately. */
+ if (incomplete
+ && check_non_deducible_conversions (parms, args, nargs, fn, strict, flags,
+ convs, explain_p))
goto fail;
- deduced:
/* All is well so far. Now, check:
[temp.deduct]
void
bar()
{
- foo<S>(); // { dg-error "unsatisfied constraints" }
+ foo<S>(); // { dg-error "no match" }
}
void bar()
{
- foo<int, char>(); // { dg-error "unsatisfied constraints" }
+ foo<int, char>(); // { dg-error "no match" }
}
void
baz()
{
- bar<int>(); // { dg-error "unsatisfied constraints" }
+ bar<int>(); // { dg-error "no match" }
/* { dg-begin-multiline-output "" }
bar<int>();
^
void
baz()
{
- bar<int, char>(); // { dg-error "unsatisfied constraints" }
- baz<2,3,4>(); // { dg-error "unsatisfied constraints" }
+ bar<int, char>(); // { dg-error "no match" }
+ baz<2,3,4>(); // { dg-error "no match" }
}
// { dg-message "typename remove_reference<T>::type" "" { target *-*-* } .-1 }
void foo() { }
-void bar() { foo<int> (); } // { dg-error "use of" }
+void bar() { foo<int> (); } // { dg-error "no match" }
void
bar()
{
- foo<char>(); // { dg-error "use of" }
+ foo<char>(); // { dg-error "no match" }
}
// PR c++/85278
// { dg-do compile { target concepts } }
+// { dg-message "candidate: .*const decltype\\(f2::a\\)&&" "" { target *-*-* } .+2 }
template<typename T>
void f2(T a)
requires requires (const decltype(a) &&x) { -x; }
{ }
int main() {
- f2<void*>(nullptr); // { dg-error "use of function .*const decltype\\(f2::a\\)&&" }
+ f2<void*>(nullptr); // { dg-error "no match" }
}
int main()
{
- f1(s); // { dg-error "unsatisfied|private" }
+ f1(s); // { dg-error "no match" }
f2(s); // { dg-error "" }
// When used in non-SFINAE contexts, make sure that we fail
S1<char> s1; // { dg-error "constraint|invalid" }
S2<int, char> s2; // { dg-error "constraint|invalid" }
- f('a'); // { dg-error "unsatisfied" }
- g(0, 'a'); // { dg-error "unsatisfied" }
+ f('a'); // { dg-error "no match" }
+ g(0, 'a'); // { dg-error "no match" }
}
template <C c>
constexpr bool f() { return true; }
-static_assert(f<double>(), ""); // { dg-error "unsatisfied|as type" }
-static_assert(f<int>(), ""); // { dg-error "unsatisfied|as type" }
+static_assert(f<double>(), ""); // { dg-error "no match" }
+static_assert(f<int>(), ""); // { dg-error "no match" }
template <class X> concept bool semiregular = allocatable<X>;
template <class X> concept bool readable = requires{requires semiregular<X>;};
template <class> int weak_input_iterator = requires{{0}->readable;};
-template <class X> bool input_iterator{weak_input_iterator<X>}; // { dg-warning "narrowing conversion" }
+template <class X> bool input_iterator{weak_input_iterator<X>}; // { dg-prune-output "narrowing conversion" }
template <class X> bool forward_iterator{input_iterator<X>};
template <class X> bool bidirectional_iterator{forward_iterator<X>};
template <class X>
--- /dev/null
+// DR 2369
+// { dg-do compile { target c++20 } }
+
+template <class T> struct Z {
+ typedef typename T::x xx;
+};
+template <class T> concept C = requires { typename T::A; };
+template <C T> typename Z<T>::xx f(void *, T); // #1
+template <class T> void f(int, T); // #2
+struct A {} a;
+struct ZZ {
+ template <class T, class = typename Z<T>::xx> operator T *();
+ operator int();
+};
+int main() {
+ ZZ zz;
+ f(1, a); // OK, deduction fails for #1 because there is no conversion from int to void*
+ f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied
+}
--- /dev/null
+// DR 2369
+// { dg-do compile { target c++20 } }
+
+template <class T> struct Z {
+ typedef typename T::x xx;
+};
+template <class T> concept C = requires { typename T::A; }; // { dg-message "T::A" }
+template <C T> typename Z<T>::xx f(void *, T); // { dg-message "not satisfied" }
+
+struct A {} a;
+struct ZZ {
+ template <class T, class = typename Z<T>::xx> operator T *();
+ operator int();
+};
+int main() {
+ ZZ zz;
+ f(1, a); // { dg-error "no match" } no conversion from int to void*
+ // { dg-message "cannot convert" "" { target *-*-* } .-1 }
+ f(zz, 42); // { dg-error "no match" } C<int> is not satisfied
+}
func(1, 2, 3);
t.func(1, 2, ""); // { dg-error "no match" }
- func(1, 2, ""); // { dg-error "unsatisfied constraints" }
+ func(1, 2, ""); // { dg-error "no match" }
}
{
return distance(I<int>{}, I<void>{});
}
-
void test()
{
- foo(0); // { dg-error "unsatisfied constraints" }
+ foo(0); // { dg-error "no match" }
}
{
f1<int>();
f1<bool>();
- f1<void>(); // { dg-error "unsatisfied" }
+ f1<void>(); // { dg-error "no match" }
f2<int>();
f2<bool>();
- f2<void>(); // { dg-error "unsatisfied" }
+ f2<void>(); // { dg-error "no match" }
data<char> x;
x.f1<int>();
void test()
{
- f1<int>(); // { dg-error "unsatisfied" }
- f2(0); // { dg-error "unsatisfied" }
+ f1<int>(); // { dg-error "no match" }
+ f2(0); // { dg-error "no match" }
- f3<int>(); // { dg-error "unsatisfied" }
- f4(0); // { dg-error "unsatisfied" }
+ f3<int>(); // { dg-error "no match" }
+ f4(0); // { dg-error "no match" }
- f5<int>(); // { dg-error "unsatisfied" }
- f6(0); // { dg-error "unsatisfied" }
+ f5<int>(); // { dg-error "no match" }
+ f6(0); // { dg-error "no match" }
}
void f3() { }
void driver2() {
- f1<S1>(); // { dg-error "unsatisfied|is private" }
- f2<S1>(); // { dg-error "unsatisfied|is private" }
- f3<S1>(); // { dg-error "unsatisfied|is private" }
+ f1<S1>(); // { dg-error "no match" }
+ f2<S1>(); // { dg-error "no match" }
+ f3<S1>(); // { dg-error "no match" }
}