aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/semantics.cc
diff options
context:
space:
mode:
authorJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
committerJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
commit071b4126c613881f4cb25b4e5c39032964827f88 (patch)
tree7ed805786566918630d1d617b1ed8f7310f5fd8e /gcc/cp/semantics.cc
parent845d23f3ea08ba873197c275a8857eee7edad996 (diff)
parentcaa1c2f42691d68af4d894a5c3e700ecd2dba080 (diff)
downloadgcc-devel/gfortran-test.zip
gcc-devel/gfortran-test.tar.gz
gcc-devel/gfortran-test.tar.bz2
Merge branch 'master' into gfortran-testdevel/gfortran-test
Diffstat (limited to 'gcc/cp/semantics.cc')
-rw-r--r--gcc/cp/semantics.cc191
1 files changed, 147 insertions, 44 deletions
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 52ecac4..1937ace 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "predict.h"
#include "memmodel.h"
#include "gimplify.h"
+#include "contracts.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -677,7 +678,7 @@ do_poplevel (tree stmt_list)
/* Begin a new scope. */
-static tree
+tree
do_pushlevel (scope_kind sk)
{
tree ret = push_stmt_list ();
@@ -1854,6 +1855,21 @@ finish_range_for_decl (tree range_for_stmt, tree decl, tree expr)
RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block);
}
+/* Begin the scope of an expansion-statement. */
+
+tree
+begin_template_for_scope (tree *init)
+{
+ tree scope = do_pushlevel (sk_template_for);
+
+ if (processing_template_decl)
+ *init = push_stmt_list ();
+ else
+ *init = NULL_TREE;
+
+ return scope;
+}
+
/* Finish a break-statement. */
tree
@@ -3992,9 +4008,15 @@ finish_compound_literal (tree type, tree compound_literal,
tree
finish_fname (tree id)
{
- tree decl;
-
- decl = fname_decl (input_location, C_RID_CODE (id), id);
+ tree decl = fname_decl (input_location, C_RID_CODE (id), id);
+ /* [expr.prim.lambda.closure]/16 "Unless the compound-statement is that
+ of a consteval-block-declaration, a variable __func__ is implicitly
+ defined...". We could be in a consteval block in a function, though,
+ and then we shouldn't warn. */
+ if (current_function_decl
+ && !current_nonlambda_function (/*only_skip_consteval_block_p=*/true))
+ pedwarn (input_location, 0, "%qD is not defined outside of function scope",
+ decl);
if (processing_template_decl && current_function_decl
&& decl != error_mark_node)
decl = DECL_NAME (decl);
@@ -4490,6 +4512,17 @@ baselink_for_fns (tree fns)
return build_baselink (conv_path, access_path, fns, /*optype=*/NULL_TREE);
}
+/* Returns true iff we are currently parsing a lambda-declarator. */
+
+static bool
+parsing_lambda_declarator ()
+{
+ cp_binding_level *b = current_binding_level;
+ while (b->kind == sk_template_parms || b->kind == sk_function_parms)
+ b = b->level_chain;
+ return b->kind == sk_lambda;
+}
+
/* Returns true iff DECL is a variable from a function outside
the current one. */
@@ -4504,7 +4537,15 @@ outer_var_p (tree decl)
/* Don't get confused by temporaries. */
&& DECL_NAME (decl)
&& (DECL_CONTEXT (decl) != current_function_decl
- || parsing_nsdmi ()));
+ || parsing_nsdmi ()
+ /* Also consider captures as outer vars if we are in
+ decltype in a lambda declarator as in:
+ auto l = [j=0]() -> decltype((j)) { ... }
+ for the sake of finish_decltype_type.
+
+ (Similar issue also affects non-lambdas, but vexing parse
+ makes it more difficult to handle than lambdas.) */
+ || parsing_lambda_declarator ()));
}
/* As above, but also checks that DECL is automatic. */
@@ -4550,7 +4591,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain, bool odr_use)
if (!mark_used (decl, complain))
return error_mark_node;
- if (parsing_nsdmi ())
+ if (parsing_nsdmi () || parsing_lambda_declarator ())
containing_function = NULL_TREE;
if (containing_function && LAMBDA_FUNCTION_P (containing_function))
@@ -7745,7 +7786,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
/* We've reached the end of a list of expanded nodes. Reset the group
start pointer. */
if (c == grp_sentinel)
- grp_start_p = NULL;
+ {
+ if (grp_start_p
+ && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p))
+ for (tree gc = *grp_start_p; gc != grp_sentinel;
+ gc = OMP_CLAUSE_CHAIN (gc))
+ OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p);
+ grp_start_p = NULL;
+ }
switch (OMP_CLAUSE_CODE (c))
{
@@ -8997,6 +9045,13 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
/* FALLTHRU */
case OMP_CLAUSE_TO:
case OMP_CLAUSE_FROM:
+ if (OMP_CLAUSE_ITERATORS (c)
+ && cp_omp_finish_iterators (OMP_CLAUSE_ITERATORS (c)))
+ {
+ t = error_mark_node;
+ break;
+ }
+ /* FALLTHRU */
case OMP_CLAUSE__CACHE_:
{
using namespace omp_addr_tokenizer;
@@ -9900,6 +9955,11 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
pc = &OMP_CLAUSE_CHAIN (c);
}
+ if (grp_start_p
+ && OMP_CLAUSE_HAS_ITERATORS (*grp_start_p))
+ for (tree gc = *grp_start_p; gc; gc = OMP_CLAUSE_CHAIN (gc))
+ OMP_CLAUSE_ITERATORS (gc) = OMP_CLAUSE_ITERATORS (*grp_start_p);
+
if (reduction_seen < 0 && (ordered_seen || schedule_seen))
reduction_seen = -2;
@@ -12598,11 +12658,14 @@ cexpr_str::extract (location_t location, const char * & msg, int &len)
CONDITION and the message text MESSAGE. LOCATION is the location
of the static assertion in the source code. When MEMBER_P, this
static assertion is a member of a class. If SHOW_EXPR_P is true,
- print the condition (because it was instantiation-dependent). */
+ print the condition (because it was instantiation-dependent).
+ If CONSTEVAL_BLOCK_P is true, this static assertion represents
+ a consteval block. */
void
finish_static_assert (tree condition, tree message, location_t location,
- bool member_p, bool show_expr_p)
+ bool member_p, bool show_expr_p,
+ bool consteval_block_p/*=false*/)
{
tsubst_flags_t complain = tf_warning_or_error;
@@ -12630,6 +12693,7 @@ finish_static_assert (tree condition, tree message, location_t location,
STATIC_ASSERT_CONDITION (assertion) = orig_condition;
STATIC_ASSERT_MESSAGE (assertion) = cstr.message;
STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+ CONSTEVAL_BLOCK_P (assertion) = consteval_block_p;
if (member_p)
maybe_add_class_template_decl_list (current_class_type,
@@ -12641,6 +12705,13 @@ finish_static_assert (tree condition, tree message, location_t location,
return;
}
+ /* Evaluate the consteval { }. This must be done only once. */
+ if (consteval_block_p)
+ {
+ cxx_constant_value (condition);
+ return;
+ }
+
/* Fold the expression and convert it to a boolean value. */
condition = contextual_conv_bool (condition, complain);
condition = fold_non_dependent_expr (condition, complain,
@@ -12890,9 +12961,9 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
}
else
{
- if (outer_automatic_var_p (STRIP_REFERENCE_REF (expr))
- && current_function_decl
- && LAMBDA_FUNCTION_P (current_function_decl))
+ tree decl = STRIP_REFERENCE_REF (expr);
+ tree lam = current_lambda_expr ();
+ if (lam && outer_automatic_var_p (decl))
{
/* [expr.prim.id.unqual]/3: If naming the entity from outside of an
unevaluated operand within S would refer to an entity captured by
@@ -12909,8 +12980,6 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
local variable inside decltype, not just decltype((x)) (PR83167).
And we don't handle nested lambdas properly, where we need to
consider the outer lambdas as well (PR112926). */
- tree decl = STRIP_REFERENCE_REF (expr);
- tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl));
tree cap = lookup_name (DECL_NAME (decl), LOOK_where::BLOCK,
LOOK_want::HIDDEN_LAMBDA);
@@ -12926,17 +12995,28 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
if (type && !TYPE_REF_P (type))
{
- tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl));
- if (WILDCARD_TYPE_P (non_reference (obtype)))
- /* We don't know what the eventual obtype quals will be. */
- goto dependent;
- auto direct_type = [](tree t){
- if (INDIRECT_TYPE_P (t))
- return TREE_TYPE (t);
- return t;
- };
- int const quals = cp_type_quals (type)
- | cp_type_quals (direct_type (obtype));
+ int quals;
+ if (current_function_decl
+ && LAMBDA_FUNCTION_P (current_function_decl)
+ && DECL_XOBJ_MEMBER_FUNCTION_P (current_function_decl))
+ {
+ tree obtype = TREE_TYPE (DECL_ARGUMENTS (current_function_decl));
+ if (WILDCARD_TYPE_P (non_reference (obtype)))
+ /* We don't know what the eventual obtype quals will be. */
+ goto dependent;
+ auto direct_type = [](tree t){
+ if (INDIRECT_TYPE_P (t))
+ return TREE_TYPE (t);
+ return t;
+ };
+ quals = (cp_type_quals (type)
+ | cp_type_quals (direct_type (obtype)));
+ }
+ else
+ /* We are in the parameter clause, trailing return type, or
+ the requires clause and have no relevant c_f_decl yet. */
+ quals = (LAMBDA_EXPR_CONST_QUAL_P (lam)
+ ? TYPE_QUAL_CONST : TYPE_UNQUALIFIED);
type = cp_build_qualified_type (type, quals);
type = build_reference_type (type);
}
@@ -13631,10 +13711,11 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_DEDUCIBLE:
return type_targs_deducible_from (type1, type2);
- /* __array_rank and __builtin_type_order are handled in
- finish_trait_expr. */
+ /* __array_rank, __builtin_type_order and __builtin_structured_binding_size
+ are handled in finish_trait_expr. */
case CPTK_RANK:
case CPTK_TYPE_ORDER:
+ case CPTK_STRUCTURED_BINDING_SIZE:
gcc_unreachable ();
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
@@ -13739,6 +13820,27 @@ same_type_ref_bind_p (cp_trait_kind kind, tree type1, tree type2)
(non_reference (to), non_reference (from))));
}
+/* Helper for finish_trait_expr and tsubst_expr. Handle
+ CPTK_STRUCTURED_BINDING_SIZE in possibly SFINAE-friendly
+ way. */
+
+tree
+finish_structured_binding_size (location_t loc, tree type,
+ tsubst_flags_t complain)
+{
+ if (TYPE_REF_P (type))
+ {
+ if (complain & tf_error)
+ error_at (loc, "%qs argument %qT is a reference",
+ "__builtin_structured_binding_size", type);
+ return error_mark_node;
+ }
+ HOST_WIDE_INT ret = cp_decomp_size (loc, type, complain);
+ if (ret == -1)
+ return error_mark_node;
+ return maybe_wrap_with_location (build_int_cst (size_type_node, ret), loc);
+}
+
/* Process a trait expression. */
tree
@@ -13751,7 +13853,7 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
if (processing_template_decl)
{
tree trait_expr = make_node (TRAIT_EXPR);
- if (kind == CPTK_RANK)
+ if (kind == CPTK_RANK || kind == CPTK_STRUCTURED_BINDING_SIZE)
TREE_TYPE (trait_expr) = size_type_node;
else if (kind == CPTK_TYPE_ORDER)
{
@@ -13868,9 +13970,22 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_UNBOUNDED_ARRAY:
case CPTK_IS_UNION:
case CPTK_IS_VOLATILE:
+ break;
+
case CPTK_RANK:
+ {
+ size_t rank = 0;
+ for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
+ ++rank;
+ return maybe_wrap_with_location (build_int_cst (size_type_node, rank),
+ loc);
+ }
+
case CPTK_TYPE_ORDER:
- break;
+ return maybe_wrap_with_location (type_order_value (type1, type2), loc);
+
+ case CPTK_STRUCTURED_BINDING_SIZE:
+ return finish_structured_binding_size (loc, type1, tf_warning_or_error);
case CPTK_IS_LAYOUT_COMPATIBLE:
if (!array_of_unknown_bound_p (type1)
@@ -13901,20 +14016,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
gcc_unreachable ();
}
- tree val;
- if (kind == CPTK_RANK)
- {
- size_t rank = 0;
- for (; TREE_CODE (type1) == ARRAY_TYPE; type1 = TREE_TYPE (type1))
- ++rank;
- val = build_int_cst (size_type_node, rank);
- }
- else if (kind == CPTK_TYPE_ORDER)
- val = type_order_value (type1, type2);
- else
- val = (trait_expr_value (kind, type1, type2)
- ? boolean_true_node : boolean_false_node);
-
+ tree val = (trait_expr_value (kind, type1, type2)
+ ? boolean_true_node : boolean_false_node);
return maybe_wrap_with_location (val, loc);
}
@@ -14111,7 +14214,7 @@ apply_deduced_return_type (tree fco, tree return_type)
result);
DECL_RESULT (fco) = result;
- if (!processing_template_decl)
+ if (!uses_template_parms (fco))
if (function *fun = DECL_STRUCT_FUNCTION (fco))
{
bool aggr = aggregate_value_p (result, fco);