case CONSTRUCTOR:
case SIZEOF_EXPR:
case PAREN_SIZEOF_EXPR:
+ /* FIXME: Add C++ codes like NOEXCEPT_EXPR (cf. unevaluated_p) as well. */
return;
case COMPOUND_EXPR:
result = tree_cons (NULL_TREE, req, result);
}
if (processing_template_decl && result != boolean_false_node)
- result = finish_requires_expr (EXPR_LOCATION (t), parms, nreverse (result));
+ result = finish_requires_expr (REQUIRES_EXPR_LOCATION (t), parms,
+ nreverse (result));
return result;
}
/* Prefer printing the instantiated mapping. */
tree atom = entry->inst_entry ? entry->inst_entry->atom : entry->atom;
if (info.noisy ())
- error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (atom)),
+ error_at (cp_expr_location (ATOMIC_CONSTR_EXPR (atom)),
"satisfaction of atomic constraint %qE depends on itself",
atom);
return error_mark_node;
if (entry->diagnose_instability)
{
auto_diagnostic_group d;
- error_at (EXPR_LOCATION (ATOMIC_CONSTR_EXPR (entry->atom)),
+ error_at (cp_expr_location (ATOMIC_CONSTR_EXPR (entry->atom)),
"satisfaction value of atomic constraint %qE changed "
"from %qE to %qE", entry->atom, entry->result, result);
inform (entry->location,
finish_requires_expr (location_t loc, tree parms, tree reqs)
{
/* Build the node. */
- tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE);
+ tree r = make_node (REQUIRES_EXPR);
+ TREE_TYPE (r) = boolean_type_node;
+ REQUIRES_EXPR_PARMS (r) = parms;
+ REQUIRES_EXPR_REQS (r) = reqs;
+ REQUIRES_EXPR_LOCATION (r) = loc;
TREE_SIDE_EFFECTS (r) = false;
TREE_CONSTANT (r) = true;
- SET_EXPR_LOCATION (r, loc);
return r;
}
case PRECONDITION_STMT: return sizeof (tree_exp);
case POSTCONDITION_STMT: return sizeof (tree_exp);
case TU_LOCAL_ENTITY: return sizeof (tree_tu_local_entity);
+ case REQUIRES_EXPR: return sizeof (tree_requires_expr);
default:
switch (TREE_CODE_CLASS (code))
{
MARK_TS_TYPED (LAMBDA_EXPR);
MARK_TS_TYPED (TYPE_ARGUMENT_PACK);
MARK_TS_TYPED (TRAIT_EXPR);
+ MARK_TS_TYPED (REQUIRES_EXPR);
/* Random new trees. */
MARK_TS_COMMON (BASELINK);
MARK_TS_EXP (DISJ_CONSTR);
MARK_TS_EXP (ATOMIC_CONSTR);
MARK_TS_EXP (NESTED_REQ);
- MARK_TS_EXP (REQUIRES_EXPR);
MARK_TS_EXP (SIMPLE_REQ);
MARK_TS_EXP (TYPE_REQ);
/* Used to represent information associated with constrained declarations. */
DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
-/* A requires-expr has three operands. The first operand is
- its parameter list (possibly NULL). The second is a list of
- requirements, which are denoted by the _REQ* tree codes
- below. The third is a TREE_VEC of template arguments to
+/* A requires-expr has three operands. REQUIRES_EXPR_PARMS is
+ its parameter list (possibly NULL). REQUIRES_EXPR_REQS is a list of
+ requirements, which are denoted by the _REQ* tree codes below.
+ REQUIRES_EXPR_EXTRA_ARGS is a TREE_VEC of template arguments to
be applied when substituting into the parameter list and
requirements, set by tsubst_requires_expr for partial instantiations. */
-DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 3)
+DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_exceptional, 0)
/* A requirement for an expression. */
DEFTREECODE (SIMPLE_REQ, "simple_req", tcc_expression, 1)
#define TU_LOCAL_ENTITY_LOCATION(NODE) \
(((struct tree_tu_local_entity *)TU_LOCAL_ENTITY_CHECK (NODE))->loc)
-\f
+/* Representation of a requires-expression. */
+struct GTY(()) tree_requires_expr {
+ struct tree_typed typed;
+ tree parms;
+ tree reqs;
+ tree extra_args;
+ location_t loc;
+};
+
/* The list of local parameters introduced by this requires-expression,
in the form of a chain of PARM_DECLs. */
#define REQUIRES_EXPR_PARMS(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 0)
+ (((struct tree_requires_expr *) REQUIRES_EXPR_CHECK (NODE))->parms)
/* A TREE_LIST of the requirements for this requires-expression.
The requirements are stored in lexical order within the TREE_VALUE
of each TREE_LIST node. The TREE_PURPOSE of each node is unused. */
#define REQUIRES_EXPR_REQS(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 1)
+ (((struct tree_requires_expr *) REQUIRES_EXPR_CHECK (NODE))->reqs)
/* Like PACK_EXPANSION_EXTRA_ARGS, for requires-expressions. */
#define REQUIRES_EXPR_EXTRA_ARGS(NODE) \
- TREE_OPERAND (TREE_CHECK (NODE, REQUIRES_EXPR), 2)
+ (((struct tree_requires_expr *) REQUIRES_EXPR_CHECK (NODE))->extra_args)
+
+/* The source location of the requires-expression. */
+#define REQUIRES_EXPR_LOCATION(NODE) \
+ (((struct tree_requires_expr *) REQUIRES_EXPR_CHECK (NODE))->loc)
/* True iff TYPE is cv decltype(^^int). */
#define REFLECTION_TYPE_P(TYPE) (TREE_CODE (TYPE) == META_TYPE)
TS_CP_TEMPLATE_INFO,
TS_CP_CONSTRAINT_INFO,
TS_CP_USERDEF_LITERAL,
- TS_CP_TU_LOCAL_ENTITY
+ TS_CP_TU_LOCAL_ENTITY,
+ TS_CP_REQUIRES_EXPR
};
/* The resulting tree type. */
userdef_literal;
struct tree_tu_local_entity GTY ((tag ("TS_CP_TU_LOCAL_ENTITY")))
tu_local_entity;
+ struct tree_requires_expr GTY ((tag ("TS_CP_REQUIRES_EXPR")))
+ requires_expr;
};
\f
return TRAIT_EXPR_LOCATION (t);
case PTRMEM_CST:
return PTRMEM_CST_LOCATION (t);
+ case REQUIRES_EXPR:
+ return REQUIRES_EXPR_LOCATION (t);
default:
return EXPR_LOCATION (t);
}
pp_cxx_right_paren (pp);
pp_cxx_whitespace (pp);
}
- pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1));
+ pp_cxx_requirement_body (pp, REQUIRES_EXPR_REQS (t));
}
/* simple-requirement:
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
case TU_LOCAL_ENTITY: return TS_CP_TU_LOCAL_ENTITY;
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
+ case REQUIRES_EXPR: return TS_CP_REQUIRES_EXPR;
default: return TS_CP_GENERIC;
}
}
cxx_pretty_printer *const pp
= static_cast <cxx_pretty_printer *> (text_output.get_printer ());
- tree parms = TREE_OPERAND (expr, 0);
+ tree parms = REQUIRES_EXPR_PARMS (expr);
pp_verbatim (pp, parms ? G_("in requirements with ")
: G_("in requirements "));
while (parms)
{
tree probe = constraints;
while (probe
- && !EXPR_LOCATION (probe)
+ && !cp_expr_location (probe)
&& TREE_CODE (probe) == TRUTH_ANDIF_EXPR)
{
tree op1 = TREE_OPERAND (probe, 1);
- probe = (EXPR_LOCATION (op1) ? op1
+ probe = (cp_expr_location (op1) ? op1
: TREE_OPERAND (probe, 0));
}
- if (probe && EXPR_LOCATION (probe))
+ if (probe && cp_expr_location (probe))
{
write_char ('Q');
write_constraint_expression (probe);
unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t)
: TREE_OPERAND_LENGTH (t));
unsigned ix = unsigned (vl);
- if (code == REQUIRES_EXPR)
- {
- /* The first operand of a REQUIRES_EXPR is a tree chain
- of PARM_DECLs. We need to stream this separately as
- otherwise we would only stream the first one. */
- chained_decls (REQUIRES_EXPR_PARMS (t));
- ++ix;
- }
for (; ix != limit; ix++)
WT (TREE_OPERAND (t, ix));
}
+ else if (code == REQUIRES_EXPR)
+ {
+ if (state)
+ state->write_location (*this, REQUIRES_EXPR_LOCATION (t));
+
+ if (streaming_p ())
+ if (has_warning_spec (t))
+ u (get_warning_spec (t));
+
+ chained_decls (REQUIRES_EXPR_PARMS (t));
+ WT (REQUIRES_EXPR_REQS (t));
+ WT (REQUIRES_EXPR_EXTRA_ARGS (t));
+ }
else
/* The CODE_CONTAINS tables were inaccurate when I started. */
gcc_checking_assert (TREE_CODE_CLASS (code) != tcc_expression
unsigned limit = (vl ? VL_EXP_OPERAND_LENGTH (t)
: TREE_OPERAND_LENGTH (t));
unsigned ix = unsigned (vl);
- if (code == REQUIRES_EXPR)
- {
- REQUIRES_EXPR_PARMS (t) = chained_decls ();
- ++ix;
- }
for (; ix != limit; ix++)
RTU (TREE_OPERAND (t, ix));
}
+ else if (code == REQUIRES_EXPR)
+ {
+ REQUIRES_EXPR_LOCATION (t) = state->read_location (*this);
+ if (has_warning_spec (t))
+ put_warning_spec (t, u ());
+
+ REQUIRES_EXPR_PARMS (t) = chained_decls ();
+ RTU (REQUIRES_EXPR_REQS (t));
+ RTU (REQUIRES_EXPR_EXTRA_ARGS (t));
+ }
/* Then by CODE. Special cases and/or 1:1 tree shape
correspondence. */
So just hash the closure type. */
return iterative_hash_template_arg (TREE_TYPE (arg), val);
+ case REQUIRES_EXPR:
+ val = iterative_hash_template_arg (REQUIRES_EXPR_PARMS (arg), val);
+ val = iterative_hash_template_arg (REQUIRES_EXPR_REQS (arg), val);
+ return iterative_hash_template_arg (REQUIRES_EXPR_EXTRA_ARGS (arg), val);
+
case CAST_EXPR:
case IMPLICIT_CONV_EXPR:
case STATIC_CAST_EXPR:
case OVERLOAD:
case BASELINK:
case ARGUMENT_PACK_SELECT:
+ case REQUIRES_EXPR:
return t;
case TRAIT_EXPR:
case REFLECT_EXPR:
return compare_reflections (t1, t2);
+ case REQUIRES_EXPR:
+ if (cp_tree_equal (REQUIRES_EXPR_PARMS (t1),
+ REQUIRES_EXPR_PARMS (t2))
+ && cp_tree_equal (REQUIRES_EXPR_REQS (t1),
+ REQUIRES_EXPR_REQS (t2))
+ && cp_tree_equal (REQUIRES_EXPR_EXTRA_ARGS (t1),
+ REQUIRES_EXPR_EXTRA_ARGS (t2)))
+ return true;
+ return false;
+
default:
break;
}
--- /dev/null
+// PR c++/126066
+// { dg-do compile { target c++20 } }
+// { dg-options "-Wall" }
+
+struct S { S& operator=(int); };
+
+void
+fn ()
+{
+ if constexpr (requires(int &a) { a = 0; }) { }
+ if constexpr (requires(S &s) { s = 0; }) { }
+}
+
+constexpr bool b = requires(int &a) { a = 0; };
+static_assert(requires(int &a) { a = 0; });