public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [pushed] c++: defer all consteval in default args [DR2631]
@ 2022-10-12 15:37 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2022-10-12 15:37 UTC (permalink / raw)
  To: gcc-patches

Tested x86_64-pc-linux-gnu, applying to trunk.

-- >8 --

The proposed resolution of CWG2631 extends our current handling of
source_location::current to all consteval functions: default arguments
are not evaluated until they're used in a call, the same should apply to
evaluation of immediate invocations.  And similarly for default member
initializers.

Previously we folded source_location::current in cp_fold_r; now we fold all
consteval calls in default arguments/member initializers in bot_replace.

	DR 2631

gcc/cp/ChangeLog:

	* cp-tree.h (source_location_current_p): Remove.
	* name-lookup.h (struct cp_binding_level): Remove
	immediate_fn_ctx_p.
	* call.cc (in_immediate_context): All default args
	and DMI are potentially immediate context.
	(immediate_invocation_p): Don't treat source_location specially.
	(struct in_consteval_if_p_temp_override): Move to cp-tree.h.
	* constexpr.cc (get_nth_callarg): Move to cp-tree.h.
	* cp-gimplify.cc (cp_fold_r): Don't fold consteval.
	* name-lookup.cc (begin_scope): Don't set immediate_fn_ctx_p.
	* parser.cc (cp_parser_lambda_declarator_opt): Likewise.
	(cp_parser_direct_declarator): Likewise.
	* pt.cc (tsubst_default_argument): Open sk_function_parms level.
	* tree.cc (source_location_current_p): Remove.
	(bot_replace): Fold consteval here.
	(break_out_target_exprs): Handle errors.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp2a/consteval-defarg3.C: New test.
---
 gcc/cp/cp-tree.h                              | 32 +++++++++++-
 gcc/cp/name-lookup.h                          |  5 +-
 gcc/cp/call.cc                                | 36 +++++--------
 gcc/cp/constexpr.cc                           | 20 -------
 gcc/cp/cp-gimplify.cc                         |  7 ---
 gcc/cp/name-lookup.cc                         |  2 -
 gcc/cp/parser.cc                              | 24 ---------
 gcc/cp/pt.cc                                  |  3 ++
 gcc/cp/tree.cc                                | 52 +++++++++----------
 .../g++.dg/cpp2a/consteval-defarg3.C          | 23 ++++++++
 10 files changed, 94 insertions(+), 110 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ab6f85a2490..80037fabb41 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2030,6 +2030,18 @@ make_temp_override (T& var, type_identity_t<T> overrider)
   return { var, overrider };
 }
 
+/* temp_override for in_consteval_if_p, which can't use make_temp_override
+   because it is a bitfield.  */
+
+struct in_consteval_if_p_temp_override {
+  bool save_in_consteval_if_p;
+  in_consteval_if_p_temp_override ()
+    : save_in_consteval_if_p (in_consteval_if_p) {}
+  void reset () { in_consteval_if_p = save_in_consteval_if_p; }
+  ~in_consteval_if_p_temp_override ()
+  { reset (); }
+};
+
 /* The cached class binding level, from the most recently exited
    class, or NULL if none.  */
 
@@ -4201,6 +4213,25 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
   for ((arg) = first_aggr_init_expr_arg ((call), &(iter)); (arg);	\
        (arg) = next_aggr_init_expr_arg (&(iter)))
 
+/* We have an expression tree T that represents a call, either CALL_EXPR
+   or AGGR_INIT_EXPR.  Return a reference to the Nth argument.  */
+
+static inline tree&
+get_nth_callarg (tree t, int n)
+{
+  switch (TREE_CODE (t))
+    {
+    case CALL_EXPR:
+      return CALL_EXPR_ARG (t, n);
+
+    case AGGR_INIT_EXPR:
+      return AGGR_INIT_EXPR_ARG (t, n);
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* VEC_INIT_EXPR accessors.  */
 #define VEC_INIT_EXPR_SLOT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 0)
 #define VEC_INIT_EXPR_INIT(NODE) TREE_OPERAND (VEC_INIT_EXPR_CHECK (NODE), 1)
@@ -7880,7 +7911,6 @@ extern tree bind_template_template_parm		(tree, tree);
 extern tree array_type_nelts_total		(tree);
 extern tree array_type_nelts_top		(tree);
 extern bool array_of_unknown_bound_p		(const_tree);
-extern bool source_location_current_p		(tree);
 extern tree break_out_target_exprs		(tree, bool = false);
 extern tree build_ctor_subob_ref		(tree, tree, tree);
 extern tree replace_placeholders		(tree, tree, bool * = NULL);
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 7201ae8ead8..9e3b69865a6 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -307,13 +307,10 @@ struct GTY(()) cp_binding_level {
      'this_entity'.  */
   unsigned defining_class_p : 1;
 
-  /* true for SK_FUNCTION_PARMS of immediate functions.  */
-  unsigned immediate_fn_ctx_p : 1;
-
   /* True for SK_FUNCTION_PARMS of a requires-expression.  */
   unsigned requires_expression: 1;
 
-  /* 21 bits left to fill a 32-bit word.  */
+  /* 22 bits left to fill a 32-bit word.  */
 };
 
 /* The binding level currently in effect.  */
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 70ec964a219..2fa33c5c604 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9301,7 +9301,8 @@ build_trivial_dtor_call (tree instance, bool no_ptr_deref)
 }
 
 /* Return true if in an immediate function context, or an unevaluated operand,
-   or a subexpression of an immediate invocation.  */
+   or a default argument/member initializer, or a subexpression of an immediate
+   invocation.  */
 
 bool
 in_immediate_context ()
@@ -9309,8 +9310,11 @@ in_immediate_context ()
   return (cp_unevaluated_operand != 0
 	  || (current_function_decl != NULL_TREE
 	      && DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
-	  || (current_binding_level->kind == sk_function_parms
-	      && current_binding_level->immediate_fn_ctx_p)
+	  /* DR 2631: default args and DMI aren't immediately evaluated.
+	     Return true here so immediate_invocation_p returns false.  */
+	  || current_binding_level->kind == sk_function_parms
+	  || current_binding_level->kind == sk_template_parms
+	  || parsing_nsdmi ()
 	  || in_consteval_if_p);
 }
 
@@ -9318,29 +9322,13 @@ in_immediate_context ()
    is an immediate invocation.  */
 
 static bool
-immediate_invocation_p (tree fn, int nargs)
+immediate_invocation_p (tree fn)
 {
   return (TREE_CODE (fn) == FUNCTION_DECL
 	  && DECL_IMMEDIATE_FUNCTION_P (fn)
-	  && !in_immediate_context ()
-	  /* As an exception, we defer std::source_location::current ()
-	     invocations until genericization because LWG3396 mandates
-	     special behavior for it.  */
-	  && (nargs > 1 || !source_location_current_p (fn)));
+	  && !in_immediate_context ());
 }
 
-/* temp_override for in_consteval_if_p, which can't use make_temp_override
-   because it is a bitfield.  */
-
-struct in_consteval_if_p_temp_override {
-  bool save_in_consteval_if_p;
-  in_consteval_if_p_temp_override ()
-    : save_in_consteval_if_p (in_consteval_if_p) {}
-  void reset () { in_consteval_if_p = save_in_consteval_if_p; }
-  ~in_consteval_if_p_temp_override ()
-  { reset (); }
-};
-
 /* Subroutine of the various build_*_call functions.  Overload resolution
    has chosen a winning candidate CAND; build up a CALL_EXPR accordingly.
    ARGS is a TREE_LIST of the unconverted arguments to the call.  FLAGS is a
@@ -9398,7 +9386,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       SET_EXPR_LOCATION (expr, input_location);
       if (TREE_THIS_VOLATILE (fn) && cfun)
 	current_function_returns_abnormally = 1;
-      if (immediate_invocation_p (fn, vec_safe_length (args)))
+      if (immediate_invocation_p (fn))
 	{
 	  tree obj_arg = NULL_TREE, exprimm = expr;
 	  if (DECL_CONSTRUCTOR_P (fn))
@@ -9543,7 +9531,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   in_consteval_if_p_temp_override icip;
   /* If the call is immediate function invocation, make sure
      taking address of immediate functions is allowed in its arguments.  */
-  if (immediate_invocation_p (STRIP_TEMPLATE (fn), nargs))
+  if (immediate_invocation_p (STRIP_TEMPLATE (fn)))
     in_consteval_if_p = true;
 
   /* The implicit parameters to a constructor are not considered by overload
@@ -10072,7 +10060,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
   if (TREE_CODE (fn) == ADDR_EXPR)
     {
       tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
-      if (immediate_invocation_p (fndecl, nargs))
+      if (immediate_invocation_p (fndecl))
 	{
 	  tree obj_arg = NULL_TREE;
 	  /* Undo convert_from_reference called by build_cxx_call.  */
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 06dcd71c926..2038f43425b 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -1324,26 +1324,6 @@ save_fundef_copy (tree fun, tree copy)
   *slot = copy;
 }
 
-/* We have an expression tree T that represents a call, either CALL_EXPR
-   or AGGR_INIT_EXPR.  Return the Nth argument.  */
-
-static inline tree
-get_nth_callarg (tree t, int n)
-{
-  switch (TREE_CODE (t))
-    {
-    case CALL_EXPR:
-      return CALL_EXPR_ARG (t, n);
-
-    case AGGR_INIT_EXPR:
-      return AGGR_INIT_EXPR_ARG (t, n);
-
-    default:
-      gcc_unreachable ();
-      return NULL;
-    }
-}
-
 /* Whether our evaluation wants a prvalue (e.g. CONSTRUCTOR or _CST),
    a glvalue (e.g. VAR_DECL or _REF), or nothing.  */
 
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d0e12c9ee17..a937060b029 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1010,13 +1010,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
 	}
       break;
 
-    case CALL_EXPR:
-      if (tree fndecl = cp_get_callee_fndecl_nofold (stmt))
-	if (DECL_IMMEDIATE_FUNCTION_P (fndecl)
-	    && source_location_current_p (fndecl))
-	  *stmt_p = stmt = cxx_constant_value (stmt);
-      break;
-
     default:
       break;
     }
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 25657cfd4c6..14e937d81cb 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -4302,8 +4302,6 @@ begin_scope (scope_kind kind, tree entity)
 
     case sk_function_parms:
       scope->keep = keep_next_level_flag;
-      if (entity)
-	scope->immediate_fn_ctx_p = DECL_IMMEDIATE_FUNCTION_P (entity);
       break;
 
     case sk_namespace:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index dc3d17c416c..4e3ed660e68 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11519,31 +11519,11 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
      opening parenthesis if present.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
-      bool is_consteval = false;
-      /* For C++20, before parsing the parameter list check if there is
-	 a consteval specifier in the corresponding decl-specifier-seq.  */
-      if (cxx_dialect >= cxx20)
-	{
-	  for (size_t n = cp_parser_skip_balanced_tokens (parser, 1);
-	       cp_lexer_nth_token_is (parser->lexer, n, CPP_KEYWORD); n++)
-	    {
-	      if (cp_lexer_peek_nth_token (parser->lexer, n)->keyword
-		  == RID_CONSTEVAL)
-		{
-		  is_consteval = true;
-		  break;
-		}
-	    }
-	}
-
       matching_parens parens;
       parens.consume_open (parser);
 
       begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
 
-      if (is_consteval)
-	current_binding_level->immediate_fn_ctx_p = true;
-
       /* Parse parameters.  */
       param_list
 	= cp_parser_parameter_declaration_clause
@@ -23186,10 +23166,6 @@ cp_parser_direct_declarator (cp_parser* parser,
 
 	      begin_scope (sk_function_parms, NULL_TREE);
 
-	      /* Signal we are in the immediate function context.  */
-	      if (flags & CP_PARSER_FLAGS_CONSTEVAL)
-		current_binding_level->immediate_fn_ctx_p = true;
-
 	      /* Parse the parameter-declaration-clause.  */
 	      params
 		= cp_parser_parameter_declaration_clause (parser, flags);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index b80e7ff1845..ec337e2349e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13933,6 +13933,8 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
   push_to_top_level ();
   push_access_scope (fn);
   push_deferring_access_checks (dk_no_deferred);
+  /* So in_immediate_context knows this is a default argument.  */
+  begin_scope (sk_function_parms, fn);
   start_lambda_scope (parm);
 
   /* The default argument expression may cause implicitly defined
@@ -13956,6 +13958,7 @@ tsubst_default_argument (tree fn, int parmnum, tree type, tree arg,
     inform (input_location,
 	    "  when instantiating default argument for call to %qD", fn);
 
+  leave_scope ();
   pop_deferring_access_checks ();
   pop_access_scope (fn);
   pop_from_top_level ();
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 3532e44279f..45348c58bb6 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3125,32 +3125,6 @@ array_type_nelts_total (tree type)
   return sz;
 }
 
-/* Return true if FNDECL is std::source_location::current () method.  */
-
-bool
-source_location_current_p (tree fndecl)
-{
-  gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL
-		       && DECL_IMMEDIATE_FUNCTION_P (fndecl));
-  if (DECL_NAME (fndecl) == NULL_TREE
-      || TREE_CODE (TREE_TYPE (fndecl)) != FUNCTION_TYPE
-      || TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != RECORD_TYPE
-      || DECL_CONTEXT (fndecl) != TREE_TYPE (TREE_TYPE (fndecl))
-      || !id_equal (DECL_NAME (fndecl), "current"))
-    return false;
-
-  tree source_location = DECL_CONTEXT (fndecl);
-  if (TYPE_NAME (source_location) == NULL_TREE
-      || TREE_CODE (TYPE_NAME (source_location)) != TYPE_DECL
-      || TYPE_IDENTIFIER (source_location) == NULL_TREE
-      || !id_equal (TYPE_IDENTIFIER (source_location),
-		    "source_location")
-      || !decl_in_std_namespace_p (TYPE_NAME (source_location)))
-    return false;
-
-  return true;
-}
-
 struct bot_data
 {
   splay_tree target_remap;
@@ -3298,7 +3272,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
    variables.  */
 
 static tree
-bot_replace (tree* t, int* /*walk_subtrees*/, void* data_)
+bot_replace (tree* t, int* walk_subtrees, void* data_)
 {
   bot_data &data = *(bot_data*)data_;
   splay_tree target_remap = data.target_remap;
@@ -3328,6 +3302,27 @@ bot_replace (tree* t, int* /*walk_subtrees*/, void* data_)
 			    /*check_access=*/false, /*nonnull=*/true,
 			    tf_warning_or_error);
     }
+  else if (cxx_dialect >= cxx20
+	   && (TREE_CODE (*t) == CALL_EXPR
+	       || TREE_CODE (*t) == AGGR_INIT_EXPR)
+	   && !in_immediate_context ())
+    {
+      /* Expand immediate invocations.  */
+      if (tree fndecl = cp_get_callee_fndecl_nofold (*t))
+	if (DECL_IMMEDIATE_FUNCTION_P (fndecl))
+	  {
+	    /* Make in_immediate_context true within the args.  */
+	    in_consteval_if_p_temp_override ito;
+	    in_consteval_if_p = true;
+	    int nargs = call_expr_nargs (*t);
+	    for (int i = 0; i < nargs; ++i)
+	      cp_walk_tree (&get_nth_callarg (*t, i), bot_replace, data_, NULL);
+	    *t = cxx_constant_value (*t);
+	    if (*t == error_mark_node)
+	      return error_mark_node;
+	    *walk_subtrees = 0;
+	  }
+    }
 
   return NULL_TREE;
 }
@@ -3353,7 +3348,8 @@ break_out_target_exprs (tree t, bool clear_location /* = false */)
   bot_data data = { target_remap, clear_location };
   if (cp_walk_tree (&t, bot_manip, &data, NULL) == error_mark_node)
     t = error_mark_node;
-  cp_walk_tree (&t, bot_replace, &data, NULL);
+  if (cp_walk_tree (&t, bot_replace, &data, NULL) == error_mark_node)
+    t = error_mark_node;
 
   if (!--target_remap_count)
     {
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C b/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C
new file mode 100644
index 00000000000..316219c6547
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-defarg3.C
@@ -0,0 +1,23 @@
+// DR 2631: default args and DMI aren't immediately evaluated
+// { dg-do compile { target c++20 } }
+// { dg-final { scan-assembler-not "foober" } }
+
+consteval int foober();
+
+int g(int = foober());
+struct A { int i = foober(); };
+template <int i = foober()> struct B { };
+struct C
+{
+  consteval C(int = foober()) { }
+};
+int h(C = C());
+
+consteval int foober() { return 42; }
+
+int main() {
+  A a;
+  B<> b;
+  g();
+  h();
+}

base-commit: 11c72f20d4d7ba1862a257cef05dc3a5e84a276d
-- 
2.31.1


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-12 15:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-12 15:37 [pushed] c++: defer all consteval in default args [DR2631] Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).