/* Processing rules for constraints.
- Copyright (C) 2013-2023 Free Software Foundation, Inc.
+ Copyright (C) 2013-2024 Free Software Foundation, Inc.
Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
This file is part of GCC.
return rhs;
if (!rhs)
return lhs;
- return finish_constraint_and_expr (input_location, lhs, rhs);
+ /* Use UNKNOWN_LOCATION so write_template_args can tell the difference
+ between this and a && the user wrote. */
+ return finish_constraint_and_expr (UNKNOWN_LOCATION, lhs, rhs);
}
/* Extract the template-id from a concept check. For standard and variable
if (!norm_cache)
norm_cache = hash_table<norm_hasher>::create_ggc (31);
- norm_entry entry = {tmpl, targs, NULL_TREE};
- norm_entry **slot = nullptr;
- hashval_t hash = 0;
- bool insert = false;
+ norm_entry *entry = nullptr;
if (!info.generate_diagnostics ())
{
/* Cache the normal form of the substituted concept-id (when not
diagnosing). */
- hash = norm_hasher::hash (&entry);
- slot = norm_cache->find_slot_with_hash (&entry, hash, NO_INSERT);
- if (slot)
+ norm_entry elt = {tmpl, targs, NULL_TREE};
+ norm_entry **slot = norm_cache->find_slot (&elt, INSERT);
+ if (*slot)
return (*slot)->norm;
- insert = true;
+ entry = ggc_alloc<norm_entry> ();
+ *entry = elt;
+ *slot = entry;
}
- /* The concept may have been ill-formed. */
tree def = get_concept_definition (DECL_TEMPLATE_RESULT (tmpl));
- if (def == error_mark_node)
- return error_mark_node;
-
info.update_context (check, args);
tree norm = normalize_expression (def, targs, info);
- if (insert)
- {
- /* Recompute SLOT since norm_cache may have been expanded during
- the recursive call. */
- slot = norm_cache->find_slot_with_hash (&entry, hash, INSERT);
- gcc_checking_assert (!*slot);
- entry.norm = norm;
- *slot = ggc_alloc<norm_entry> ();
- **slot = entry;
- }
+ if (entry)
+ entry->norm = norm;
return norm;
}
if (DECL_UNIQUE_FRIEND_P (decl) && DECL_TEMPLATE_INFO (decl))
{
tree tmpl = DECL_TI_TEMPLATE (decl);
- tree outer_args = outer_template_args (tmpl);
+ tree outer_args = outer_template_args (decl);
processing_template_decl_sentinel s;
if (PRIMARY_TEMPLATE_P (tmpl)
|| uses_template_parms (outer_args))
check = ovl_make (tmpl);
check = build_concept_check (check, arg, args, tf_warning_or_error);
- /* Make the check a fold-expression if needed. */
+ /* Make the check a fold-expression if needed.
+ Use UNKNOWN_LOCATION so write_template_args can tell the
+ difference between this and a fold the user wrote. */
if (apply_to_each_p && declared_pack_p)
- check = finish_left_unary_fold_expr (check, TRUTH_ANDIF_EXPR);
+ check = finish_left_unary_fold_expr (UNKNOWN_LOCATION,
+ check, TRUTH_ANDIF_EXPR);
return check;
}
*slot = entry;
}
else
- /* We shouldn't get here, but if we do, let's just leave 'entry'
- empty, effectively disabling the cache. */
- return;
+ {
+ /* We're evaluating this atom for the first time, and doing so noisily.
+ This shouldn't happen outside of error recovery situations involving
+ unstable satisfaction. Let's just leave 'entry' empty, effectively
+ disabling the cache, and remove the empty slot. */
+ gcc_checking_assert (seen_error ());
+ /* Appease hash_table::check_complete_insertion. */
+ *slot = ggc_alloc<sat_entry> ();
+ sat_cache->clear_slot (slot);
+ }
}
/* Returns the cached satisfaction result if we have one and we're not
if (entry->evaluating)
{
/* If we get here, it means satisfaction is self-recursive. */
- gcc_checking_assert (!entry->result);
+ gcc_checking_assert (!entry->result || seen_error ());
if (info.noisy ())
error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (entry->atom)),
"satisfaction of atomic constraint %qE depends on itself",
}
else
{
- result = maybe_constant_value (result, NULL_TREE,
- /*manifestly_const_eval=*/true);
+ result = maybe_constant_value (result, NULL_TREE, mce_true);
if (!TREE_CONSTANT (result))
result = error_mark_node;
}
tree t1 = TRAIT_EXPR_TYPE1 (expr);
tree t2 = TRAIT_EXPR_TYPE2 (expr);
+ if (t2 && TREE_CODE (t2) == TREE_VEC)
+ {
+ /* Convert the TREE_VEC of arguments into a TREE_LIST, since we can't
+ directly print a TREE_VEC but we can a TREE_LIST via the E format
+ specifier. */
+ tree list = NULL_TREE;
+ for (tree t : tree_vec_range (t2))
+ list = tree_cons (NULL_TREE, t, list);
+ t2 = nreverse (list);
+ }
switch (TRAIT_EXPR_KIND (expr))
{
case CPTK_HAS_NOTHROW_ASSIGN:
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
inform (loc, " %qT is not trivially destructible", t1);
break;
+ case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
+ inform (loc, " %qT does not have unique object representations", t1);
+ break;
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
inform (loc, " %qT does not have a virtual destructor", t1);
break;
case CPTK_IS_ABSTRACT:
inform (loc, " %qT is not an abstract class", t1);
break;
+ case CPTK_IS_AGGREGATE:
+ inform (loc, " %qT is not an aggregate", t1);
+ break;
+ case CPTK_IS_ARRAY:
+ inform (loc, " %qT is not an array", t1);
+ break;
+ case CPTK_IS_ASSIGNABLE:
+ inform (loc, " %qT is not assignable from %qT", t1, t2);
+ break;
case CPTK_IS_BASE_OF:
inform (loc, " %qT is not a base of %qT", t1, t2);
break;
+ case CPTK_IS_BOUNDED_ARRAY:
+ inform (loc, " %qT is not a bounded array", t1);
+ break;
case CPTK_IS_CLASS:
inform (loc, " %qT is not a class", t1);
break;
+ case CPTK_IS_CONSTRUCTIBLE:
+ if (!t2)
+ inform (loc, " %qT is not default constructible", t1);
+ else
+ inform (loc, " %qT is not constructible from %qE", t1, t2);
+ break;
+ case CPTK_IS_CONVERTIBLE:
+ inform (loc, " %qT is not convertible from %qE", t2, t1);
+ break;
case CPTK_IS_EMPTY:
inform (loc, " %qT is not an empty class", t1);
break;
case CPTK_IS_FINAL:
inform (loc, " %qT is not a final class", t1);
break;
+ case CPTK_IS_FUNCTION:
+ inform (loc, " %qT is not a function", t1);
+ break;
case CPTK_IS_LAYOUT_COMPATIBLE:
inform (loc, " %qT is not layout compatible with %qT", t1, t2);
break;
case CPTK_IS_LITERAL_TYPE:
inform (loc, " %qT is not a literal type", t1);
break;
+ case CPTK_IS_MEMBER_FUNCTION_POINTER:
+ inform (loc, " %qT is not a member function pointer", t1);
+ break;
+ case CPTK_IS_MEMBER_OBJECT_POINTER:
+ inform (loc, " %qT is not a member object pointer", t1);
+ break;
+ case CPTK_IS_MEMBER_POINTER:
+ inform (loc, " %qT is not a member pointer", t1);
+ break;
+ case CPTK_IS_NOTHROW_ASSIGNABLE:
+ inform (loc, " %qT is not nothrow assignable from %qT", t1, t2);
+ break;
+ case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+ if (!t2)
+ inform (loc, " %qT is not nothrow default constructible", t1);
+ else
+ inform (loc, " %qT is not nothrow constructible from %qE", t1, t2);
+ break;
+ case CPTK_IS_NOTHROW_CONVERTIBLE:
+ inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
+ break;
+ case CPTK_IS_OBJECT:
+ inform (loc, " %qT is not an object type", t1);
+ break;
case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
inform (loc, " %qT is not pointer-interconvertible base of %qT",
t1, t2);
case CPTK_IS_POLYMORPHIC:
inform (loc, " %qT is not a polymorphic type", t1);
break;
+ case CPTK_IS_REFERENCE:
+ inform (loc, " %qT is not a reference", t1);
+ break;
case CPTK_IS_SAME:
inform (loc, " %qT is not the same as %qT", t1, t2);
break;
+ case CPTK_IS_SCOPED_ENUM:
+ inform (loc, " %qT is not a scoped enum", t1);
+ break;
case CPTK_IS_STD_LAYOUT:
inform (loc, " %qT is not an standard layout type", t1);
break;
case CPTK_IS_TRIVIAL:
inform (loc, " %qT is not a trivial type", t1);
break;
- case CPTK_IS_UNION:
- inform (loc, " %qT is not a union", t1);
- break;
- case CPTK_IS_AGGREGATE:
- inform (loc, " %qT is not an aggregate", t1);
- break;
- case CPTK_IS_TRIVIALLY_COPYABLE:
- inform (loc, " %qT is not trivially copyable", t1);
- break;
- case CPTK_IS_ASSIGNABLE:
- inform (loc, " %qT is not assignable from %qT", t1, t2);
- break;
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
inform (loc, " %qT is not trivially assignable from %qT", t1, t2);
break;
- case CPTK_IS_NOTHROW_ASSIGNABLE:
- inform (loc, " %qT is not nothrow assignable from %qT", t1, t2);
- break;
- case CPTK_IS_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not default constructible", t1);
- else
- inform (loc, " %qT is not constructible from %qE", t1, t2);
- break;
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
if (!t2)
inform (loc, " %qT is not trivially default constructible", t1);
else
inform (loc, " %qT is not trivially constructible from %qE", t1, t2);
break;
- case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not nothrow default constructible", t1);
- else
- inform (loc, " %qT is not nothrow constructible from %qE", t1, t2);
- break;
- case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
- inform (loc, " %qT does not have unique object representations", t1);
- break;
- case CPTK_IS_CONVERTIBLE:
- inform (loc, " %qT is not convertible from %qE", t2, t1);
+ case CPTK_IS_TRIVIALLY_COPYABLE:
+ inform (loc, " %qT is not trivially copyable", t1);
break;
- case CPTK_IS_NOTHROW_CONVERTIBLE:
- inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
+ case CPTK_IS_UNION:
+ inform (loc, " %qT is not a union", t1);
break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
inform (loc, " %qT is not a reference that binds to a temporary "
inform (loc, " %qT is not a reference that binds to a temporary "
"object of type %qT (copy-initialization)", t1, t2);
break;
+ case CPTK_IS_DEDUCIBLE:
+ inform (loc, " %qD is not deducible from %qT", t1, t2);
+ break;
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
case CPTK_##CODE:
#include "cp-trait.def"