[C++ PATCH] Implement P1073R3: Immediate functions (PR c++/88335, take 3)

Jakub Jelinek jakub@redhat.com
Thu Oct 31 17:22:00 GMT 2019


On Wed, Oct 30, 2019 at 05:06:00PM -0400, Jason Merrill wrote:
> build_cplus_new does the magic of replacing a dummy argument, e.g.
> 
> >           if (obj_arg && is_dummy_object (obj_arg))
> >             {
> >               call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
> >               obj_arg = NULL_TREE;
> >             }
> 
> And then if the return value from build_special_member_call is
> TREE_CONSTANT, we can return that directly from build_value_init rather than
> look for an AGGR_INIT_EXPR.

Ok, that works.

> Hmm, it shouldn't be hard to scan ahead to see if there's a consteval after
> the parameter list.

Done it that way, we already have all the needed skip routines so nothing
really needs to be parsed, just skipped.

I've added some further tests and run into another issue, that for const
or constexpr vars with consteval ctor constexpr evaluation complained that
the ctor can't modify non-static data members in the object.  The problem
was that obj_arg passed in that case was *(S *)&var where var had const S
type, so had to add code to pass var in that case.

Bootstrapped/regtested on x86_64-linux and i686-linux, all tests pass now,
ok for trunk?

2019-10-31  Jakub Jelinek  <jakub@redhat.com>

	PR c++/88335 - Implement P1073R3: Immediate functions
c-family/
	* c-common.h (enum rid): Add RID_CONSTEVAL.
	* c-common.c (c_common_reswords): Add consteval.
cp/
	* cp-tree.h (struct lang_decl_fn): Add immediate_fn_p bit.
	(DECL_IMMEDIATE_FUNCTION_P, SET_DECL_IMMEDIATE_FUNCTION_P): Define.
	(enum cp_decl_spec): Add ds_consteval.
	(fold_non_dependent_expr): Add another tree argument defaulted to
	NULL_TREE.
	* name-lookup.h (struct cp_binding_level): Add immediate_fn_ctx_p
	member.
	* parser.c (cp_keyword_starts_decl_specifier_p): Adjust comments
	for C++11 and C++20 specifiers.  Handle RID_CONSTEVAL.
	(CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Adjust comment.
	(CP_PARSER_FLAGS_CONSTEVAL): New.
	(cp_parser_skip_balanced_tokens): New forward declaration.
	(cp_parser_lambda_declarator_opt): Handle ds_consteval.  Set
	current_binding_level->immediate_fn_ctx_p before parsing parameter
	list if decl-specifier-seq contains consteval specifier.
	(cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
	(cp_parser_explicit_instantiation): Diagnose explicit instantiation
	with consteval specifier.
	(cp_parser_init_declarator): For consteval or into flags
	CP_PARSER_FLAGS_CONSTEVAL.
	(cp_parser_direct_declarator): If CP_PARSER_FLAGS_CONSTEVAL, set
	current_binding_level->immediate_fn_ctx_p in the sk_function_parms
	scope.
	(set_and_check_decl_spec_loc): Add consteval entry, formatting fix.
	* call.c (build_addr_func): For direct calls to immediate functions
	use build_address rather than decay_conversion.
	(build_over_call): Evaluate immediate function invocations.
	* error.c (dump_function_decl): Handle DECL_IMMEDIATE_FUNCTION_P.
	* semantics.c (expand_or_defer_fn_1): Use tentative linkage and don't
	call mark_needed for immediate functions.
	* typeck.c (cxx_sizeof_or_alignof_expr): Likewise.  Formatting fix.
	(cp_build_addr_expr_1): Reject taking address of immediate function
	outside of immediate function.
	* decl.c (validate_constexpr_redeclaration): Diagnose consteval
	vs. non-consteval or vice versa redeclaration.  Use
	SET_DECL_IMMEDIATE_FUNCTION_P if new_decl is immediate function.
	(check_tag_decl): Use %qs with keyword string to simplify translation.
	Handle ds_consteval.
	(start_decl): Adjust diagnostics for static or thread_local variables
	in immediate functions.
	(grokfndecl): Call sorry_at on virtual consteval.  Use %qs with keyword
	to string to simplify translation.  Diagnose consteval main.  Use
	SET_DECL_IMMEDIATE_FUNCTION_P for consteval.
	(grokdeclarator): Handle consteval.  Use %qs with keyword strings to
	simplify translation.  Use separate ifs instead of chained else if
	for invalid specifiers.  For constinit clear constinit_p rather than
	constexpr_p.
	* constexpr.c (find_immediate_fndecl): New function.
	(cxx_eval_outermost_constant_expr): Allow consteval calls returning
	void.  Diagnose returning address of immediate function from consteval
	evaluation.
	(fold_non_dependent_expr_template): Add OBJECT argument, pass it
	through to cxx_eval_outermost_constant_expr.
	(fold_non_dependent_expr): Add OBJECT argument, pass it through to
	fold_non_dependent_expr_template.
	(fold_non_dependent_init): Adjust fold_non_dependent_expr_template
	caller.
	* method.c (defaulted_late_check): Adjust diagnostics for consteval.
	* lambda.c (maybe_add_lambda_conv_op): Copy over
	DECL_DECLARED_CONSTEXPR_P and DECL_IMMEDIATE_FUNCTION_P bits from
	callop to both artificial functions.
	* init.c (build_value_init): Don't do further processing if
	build_special_member_call returned a TREE_CONSTANT.  Formatting fix.
testsuite/
	* g++.dg/cpp2a/consteval1.C: New test.
	* g++.dg/cpp2a/consteval2.C: New test.
	* g++.dg/cpp2a/consteval3.C: New test.
	* g++.dg/cpp2a/consteval4.C: New test.
	* g++.dg/cpp2a/consteval5.C: New test.
	* g++.dg/cpp2a/consteval6.C: New test.
	* g++.dg/cpp2a/consteval7.C: New test.
	* g++.dg/cpp2a/consteval8.C: New test.
	* g++.dg/cpp2a/consteval9.C: New test.
	* g++.dg/cpp2a/consteval10.C: New test.
	* g++.dg/cpp2a/consteval11.C: New test.
	* g++.dg/cpp2a/consteval12.C: New test.
	* g++.dg/cpp2a/consteval13.C: New test.
	* g++.dg/cpp2a/consteval14.C: New test.
	* g++.dg/ext/consteval1.C: New test.

--- gcc/c-family/c-common.h.jj	2019-10-29 08:48:37.533543690 +0100
+++ gcc/c-family/c-common.h	2019-10-31 13:38:16.850178342 +0100
@@ -181,7 +181,7 @@ enum rid
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
   /* C++20 */
-  RID_CONSTINIT,
+  RID_CONSTINIT, RID_CONSTEVAL,
 
   /* char8_t */
   RID_CHAR8,
--- gcc/c-family/c-common.c.jj	2019-10-29 08:48:37.485544436 +0100
+++ gcc/c-family/c-common.c	2019-10-31 13:38:16.852178311 +0100
@@ -459,6 +459,7 @@ const struct c_common_resword c_common_r
   { "char32_t",		RID_CHAR32,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "class",		RID_CLASS,	D_CXX_OBJC | D_CXXWARN },
   { "const",		RID_CONST,	0 },
+  { "consteval",	RID_CONSTEVAL,	D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "constexpr",	RID_CONSTEXPR,	D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "constinit",	RID_CONSTINIT,	D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "const_cast",	RID_CONSTCAST,	D_CXXONLY | D_CXXWARN },
--- gcc/cp/cp-tree.h.jj	2019-10-31 11:01:27.079215972 +0100
+++ gcc/cp/cp-tree.h	2019-10-31 13:38:16.854178280 +0100
@@ -2696,7 +2696,8 @@ struct GTY(()) lang_decl_fn {
   unsigned hidden_friend_p : 1;
   unsigned omp_declare_reduction_p : 1;
   unsigned has_dependent_explicit_spec_p : 1;
-  unsigned spare : 12;
+  unsigned immediate_fn_p : 1;
+  unsigned spare : 11;
 
   /* 32-bits padding on 64-bit host.  */
 
@@ -3210,6 +3211,15 @@ struct GTY(()) lang_decl {
 #define DECL_DECLARED_CONSTEXPR_P(DECL) \
   DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
 
+/* True if FNDECL is an immediate function.  */
+#define DECL_IMMEDIATE_FUNCTION_P(NODE) \
+  (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (NODE)))	\
+   ? LANG_DECL_FN_CHECK (NODE)->immediate_fn_p				\
+   : false)
+#define SET_DECL_IMMEDIATE_FUNCTION_P(NODE) \
+  (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)),			\
+   LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
+
 // True if NODE was declared as 'concept'.  The flag implies that the
 // declaration is constexpr, that the declaration cannot be specialized or
 // refined, and that the result type must be convertible to bool.
@@ -5873,6 +5883,7 @@ enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7818,7 +7829,7 @@ extern tree maybe_constant_value		(tree,
 extern tree maybe_constant_init			(tree, tree = NULL_TREE, bool = false);
 extern tree fold_non_dependent_expr		(tree,
 						 tsubst_flags_t = tf_warning_or_error,
-						 bool = false);
+						 bool = false, tree = NULL_TREE);
 extern tree fold_non_dependent_init		(tree,
 						 tsubst_flags_t = tf_warning_or_error,
 						 bool = false);
--- gcc/cp/name-lookup.h.jj	2019-10-24 14:46:35.279746493 +0200
+++ gcc/cp/name-lookup.h	2019-10-31 13:38:16.855178265 +0100
@@ -233,7 +233,10 @@ struct GTY(()) cp_binding_level {
      'this_entity'.  */
   unsigned defining_class_p : 1;
 
-  /* 23 bits left to fill a 32-bit word.  */
+  /* true for SK_FUNCTION_PARMS of immediate functions.  */
+  unsigned immediate_fn_ctx_p : 1;
+
+  /* 22 bits left to fill a 32-bit word.  */
 };
 
 /* The binding level currently in effect.  */
--- gcc/cp/parser.c.jj	2019-10-31 08:08:42.959785112 +0100
+++ gcc/cp/parser.c	2019-10-31 15:39:59.294854493 +0100
@@ -998,11 +998,13 @@ cp_keyword_starts_decl_specifier_p (enum
       /* GNU extensions.  */
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
-      /* C++0x extensions.  */
+      /* C++11 extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
     case RID_CONSTEXPR:
+      /* C++20 extensions.  */
     case RID_CONSTINIT:
+    case RID_CONSTEVAL:
       return true;
 
     default:
@@ -1807,12 +1809,15 @@ enum
   /* When parsing a decl-specifier-seq, only allow type-specifier or
      constexpr.  */
   CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
-  /* When parsing a decl-specifier-seq, only allow mutable or constexpr.  */
+  /* When parsing a decl-specifier-seq, only allow mutable, constexpr or
+     for C++2A consteval.  */
   CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
   /* When parsing a decl-specifier-seq, allow missing typename.  */
   CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
   /* When parsing of the noexcept-specifier should be delayed.  */
-  CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40
+  CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40,
+  /* When parsing a consteval declarator.  */
+  CP_PARSER_FLAGS_CONSTEVAL = 0x80
 };
 
 /* This type is used for parameters and variables which hold
@@ -2671,6 +2676,7 @@ static bool cp_parser_init_statement_p
   (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
+static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
 
 // -------------------------------------------------------------------------- //
 // Unevaluated Operand Guard
@@ -10903,11 +10909,39 @@ cp_parser_lambda_declarator_opt (cp_pars
      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 >= cxx2a)
+	{
+	  for (size_t n = cp_parser_skip_balanced_tokens (parser, 1); ; n++)
+	    {
+	      size_t after = cp_parser_skip_attributes_opt (parser, n);
+	      if (after > n)
+		{
+		  n = after - 1;
+		  continue;
+		}
+
+	      if (!cp_lexer_nth_token_is (parser->lexer, n, CPP_KEYWORD))
+		break;
+	      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
@@ -10992,6 +11026,9 @@ cp_parser_lambda_declarator_opt (cp_pars
 		    "lambda only available with %<-std=c++17%> or "
 		    "%<-std=gnu++17%>");
       }
+    if (lambda_specs.locations[ds_consteval])
+      return_type_specs.locations[ds_consteval]
+	= lambda_specs.locations[ds_consteval];
 
     p = obstack_alloc (&declarator_obstack, 0);
 
@@ -14052,6 +14089,11 @@ cp_parser_decl_specifier_seq (cp_parser*
 	  cp_lexer_consume_token (parser->lexer);
 	  break;
 
+	case RID_CONSTEVAL:
+	  ds = ds_consteval;
+	  cp_lexer_consume_token (parser->lexer);
+	  break;
+
         case RID_CONCEPT:
           ds = ds_concept;
           cp_lexer_consume_token (parser->lexer);
@@ -14169,7 +14211,8 @@ cp_parser_decl_specifier_seq (cp_parser*
       if (found_decl_spec
 	  && (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
 	  && token->keyword != RID_MUTABLE
-	  && token->keyword != RID_CONSTEXPR)
+	  && token->keyword != RID_CONSTEXPR
+	  && token->keyword != RID_CONSTEVAL)
 	error_at (token->location, "%qD invalid in lambda",
 		  ridpointers[token->keyword]);
 
@@ -17310,6 +17353,10 @@ cp_parser_explicit_instantiation (cp_par
 	    permerror (decl_specifiers.locations[ds_constexpr],
 		       "explicit instantiation shall not use"
 		       " %<constexpr%> specifier");
+	  if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_consteval))
+	    permerror (decl_specifiers.locations[ds_consteval],
+		       "explicit instantiation shall not use"
+		       " %<consteval%> specifier");
 
 	  decl = grokdeclarator (declarator, &decl_specifiers,
 				 NORMAL, 0, &decl_specifiers.attributes);
@@ -20295,6 +20342,9 @@ cp_parser_init_declarator (cp_parser* pa
   bool saved_default_arg_ok_p = parser->default_arg_ok_p;
   location_t tmp_init_loc = UNKNOWN_LOCATION;
 
+  if (decl_spec_seq_has_spec_p (decl_specifiers, ds_consteval))
+    flags |= CP_PARSER_FLAGS_CONSTEVAL;
+
   /* Gather the attributes that were provided with the
      decl-specifiers.  */
   prefix_attributes = decl_specifiers->attributes;
@@ -20939,6 +20989,10 @@ cp_parser_direct_declarator (cp_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);
@@ -29960,9 +30014,10 @@ set_and_check_decl_spec_loc (cp_decl_spe
 	    "friend",
 	    "typedef",
 	    "using",
-            "constexpr",
+	    "constexpr",
 	    "__complex",
-	    "constinit"
+	    "constinit",
+	    "consteval"
 	  };
 	  gcc_rich_location richloc (location);
 	  richloc.add_fixit_remove ();
--- gcc/cp/call.c.jj	2019-10-30 08:13:50.099831610 +0100
+++ gcc/cp/call.c	2019-10-31 14:29:17.246084906 +0100
@@ -289,6 +289,9 @@ build_addr_func (tree function, tsubst_f
 	}
       function = build_address (function);
     }
+  else if (TREE_CODE (function) == FUNCTION_DECL
+	   && DECL_IMMEDIATE_FUNCTION_P (function))
+    function = build_address (function);
   else
     function = decay_conversion (function, complain, /*reject_builtin=*/false);
 
@@ -8145,6 +8148,40 @@ build_over_call (struct z_candidate *can
 				   addr, nargs, argarray);
       if (TREE_THIS_VOLATILE (fn) && cfun)
 	current_function_returns_abnormally = 1;
+      if (TREE_CODE (fn) == FUNCTION_DECL
+	  && DECL_IMMEDIATE_FUNCTION_P (fn)
+	  && (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))
+	{
+	  tree obj_arg = NULL_TREE, exprimm = expr;
+	  if (DECL_CONSTRUCTOR_P (fn))
+	    obj_arg = first_arg;
+	  if (obj_arg
+	      && is_dummy_object (obj_arg)
+	      && !type_dependent_expression_p (obj_arg))
+	    {
+	      exprimm = build_cplus_new (DECL_CONTEXT (fn), expr, complain);
+	      obj_arg = NULL_TREE;
+	    }
+	  /* Look through *(const T *)&obj.  */
+	  else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+	    {
+	      tree addr = TREE_OPERAND (obj_arg, 0);
+	      STRIP_NOPS (addr);
+	      if (TREE_CODE (addr) == ADDR_EXPR)
+		{
+		  tree typeo = TREE_TYPE (obj_arg);
+		  tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+		  if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+		    obj_arg = TREE_OPERAND (addr, 0);
+		}
+	    }
+	  fold_non_dependent_expr (exprimm, complain,
+				   /*manifestly_const_eval=*/true,
+				   obj_arg);
+	}
       return convert_from_reference (expr);
     }
 
@@ -8744,6 +8781,40 @@ build_over_call (struct z_candidate *can
       if (TREE_CODE (c) == CALL_EXPR)
 	TREE_NO_WARNING (c) = 1;
     }
+  if (TREE_CODE (fn) == ADDR_EXPR)
+    {
+      tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
+      if (TREE_CODE (fndecl) == FUNCTION_DECL
+	  && DECL_IMMEDIATE_FUNCTION_P (fndecl)
+	  && (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))
+	{
+	  tree obj_arg = NULL_TREE;
+	  if (DECL_CONSTRUCTOR_P (fndecl))
+	    obj_arg = cand->first_arg ? cand->first_arg : (*args)[0];
+	  if (obj_arg && is_dummy_object (obj_arg))
+	    {
+	      call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
+	      obj_arg = NULL_TREE;
+	    }
+	  /* Look through *(const T *)&obj.  */
+	  else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+	    {
+	      tree addr = TREE_OPERAND (obj_arg, 0);
+	      STRIP_NOPS (addr);
+	      if (TREE_CODE (addr) == ADDR_EXPR)
+		{
+		  tree typeo = TREE_TYPE (obj_arg);
+		  tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+		  if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+		    obj_arg = TREE_OPERAND (addr, 0);
+		}
+	    }
+	  call = cxx_constant_value (call, obj_arg);
+	}
+    }
   return call;
 }
 
--- gcc/cp/error.c.jj	2019-10-24 14:46:35.079749570 +0200
+++ gcc/cp/error.c	2019-10-31 13:38:16.862178157 +0100
@@ -1652,7 +1652,9 @@ dump_function_decl (cxx_pretty_printer *
         {
           if (DECL_DECLARED_CONCEPT_P (t))
             pp_cxx_ws_string (pp, "concept");
-          else
+	  else if (DECL_IMMEDIATE_FUNCTION_P (t))
+	    pp_cxx_ws_string (pp, "consteval");
+	  else
 	    pp_cxx_ws_string (pp, "constexpr");
 	}
     }
--- gcc/cp/semantics.c.jj	2019-10-24 14:46:35.122748909 +0200
+++ gcc/cp/semantics.c	2019-10-31 13:38:16.863178141 +0100
@@ -4428,7 +4428,7 @@ expand_or_defer_fn_1 (tree fn)
       if (DECL_INTERFACE_KNOWN (fn))
 	/* We've already made a decision as to how this function will
 	   be handled.  */;
-      else if (!at_eof)
+      else if (!at_eof || DECL_IMMEDIATE_FUNCTION_P (fn))
 	tentative_decl_linkage (fn);
       else
 	import_export_decl (fn);
@@ -4439,6 +4439,7 @@ expand_or_defer_fn_1 (tree fn)
 	 be emitted; there may be callers in other DLLs.  */
       if (DECL_DECLARED_INLINE_P (fn)
 	  && !DECL_REALLY_EXTERN (fn)
+	  && !DECL_IMMEDIATE_FUNCTION_P (fn)
 	  && (flag_keep_inline_functions
 	      || (flag_keep_inline_dllexport
 		  && lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))))
--- gcc/cp/typeck.c.jj	2019-10-30 22:53:06.004252576 +0100
+++ gcc/cp/typeck.c	2019-10-31 13:38:16.864178126 +0100
@@ -6177,6 +6177,16 @@ cp_build_addr_expr_1 (tree arg, bool str
     {
       tree stripped_arg = tree_strip_any_location_wrapper (arg);
       if (TREE_CODE (stripped_arg) == FUNCTION_DECL
+	  && DECL_IMMEDIATE_FUNCTION_P (stripped_arg)
+	  && (current_function_decl == NULL_TREE
+	      || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+	{
+	  if (complain & tf_error)
+	    error ("taking address of an immediate function %qD",
+		   stripped_arg);
+	  return error_mark_node;
+	}
+      if (TREE_CODE (stripped_arg) == FUNCTION_DECL
 	  && !mark_used (stripped_arg, complain) && !(complain & tf_error))
 	return error_mark_node;
       val = build_address (arg);
--- gcc/cp/decl.c.jj	2019-10-31 08:10:14.517368027 +0100
+++ gcc/cp/decl.c	2019-10-31 13:38:16.865178110 +0100
@@ -1225,7 +1225,13 @@ validate_constexpr_redeclaration (tree o
     return true;
   if (DECL_DECLARED_CONSTEXPR_P (old_decl)
       == DECL_DECLARED_CONSTEXPR_P (new_decl))
-    return true;
+    {
+      if (TREE_CODE (old_decl) != FUNCTION_DECL)
+	return true;
+      if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+	  == DECL_IMMEDIATE_FUNCTION_P (new_decl))
+	return true;
+    }
   if (TREE_CODE (old_decl) == FUNCTION_DECL)
     {
       if (fndecl_built_in_p (old_decl))
@@ -1233,6 +1239,8 @@ validate_constexpr_redeclaration (tree o
 	  /* Hide a built-in declaration.  */
 	  DECL_DECLARED_CONSTEXPR_P (old_decl)
 	    = DECL_DECLARED_CONSTEXPR_P (new_decl);
+	  if (DECL_IMMEDIATE_FUNCTION_P (new_decl))
+	    SET_DECL_IMMEDIATE_FUNCTION_P (old_decl);
 	  return true;
 	}
       /* 7.1.5 [dcl.constexpr]
@@ -1242,9 +1250,14 @@ validate_constexpr_redeclaration (tree o
 	  && DECL_TEMPLATE_SPECIALIZATION (new_decl))
 	return true;
 
+      const char *kind = "constexpr";
+      if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+	  || DECL_IMMEDIATE_FUNCTION_P (new_decl))
+	kind = "consteval";
       error_at (DECL_SOURCE_LOCATION (new_decl),
-		"redeclaration %qD differs in %<constexpr%> "
-		"from previous declaration", new_decl);
+		"redeclaration %qD differs in %qs "
+		"from previous declaration", new_decl,
+		kind);
       inform (DECL_SOURCE_LOCATION (old_decl),
 	      "previous declaration %qD", old_decl);
       return false;
@@ -5024,12 +5037,15 @@ check_tag_decl (cp_decl_specifier_seq *d
       else if (saw_typedef)
 	warning_at (declspecs->locations[ds_typedef], 0,
 		    "%<typedef%> was ignored in this declaration");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constexpr))
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
         error_at (declspecs->locations[ds_constexpr],
-		  "%<constexpr%> cannot be used for type declarations");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constinit))
+		  "%qs cannot be used for type declarations", "constexpr");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
 	error_at (declspecs->locations[ds_constinit],
-		  "%<constinit%> cannot be used for type declarations");
+		  "%qs cannot be used for type declarations", "constinit");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_consteval))
+	error_at (declspecs->locations[ds_consteval],
+		  "%qs cannot be used for type declarations", "consteval");
     }
 
   if (declspecs->attributes && warn_attributes && declared_type)
@@ -5387,11 +5403,14 @@ start_decl (const cp_declarator *declara
       bool ok = false;
       if (CP_DECL_THREAD_LOCAL_P (decl))
 	error_at (DECL_SOURCE_LOCATION (decl),
-		  "%qD declared %<thread_local%> in %<constexpr%> function",
-		  decl);
+		  "%qD declared %<thread_local%> in %qs function", decl,
+		  DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+		  ? "consteval" : "constexpr");
       else if (TREE_STATIC (decl))
 	error_at (DECL_SOURCE_LOCATION (decl),
-		  "%qD declared %<static%> in %<constexpr%> function", decl);
+		  "%qD declared %<static%> in %qs function", decl,
+		  DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+		  ? "consteval" : "constexpr");
       else
 	ok = true;
       if (!ok)
@@ -9342,6 +9361,15 @@ grokfndecl (tree ctype,
 	  }
     }
 
+  /* FIXME: For now.  */
+  if (virtualp && (inlinep & 8) != 0)
+    {
+      sorry_at (DECL_SOURCE_LOCATION (decl),
+		"%<virtual%> %<consteval%> method %qD not supported yet",
+		decl);
+      inlinep &= ~8;
+    }
+
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
@@ -9389,7 +9417,10 @@ grokfndecl (tree ctype,
 		  "cannot declare %<::main%> to be inline");
       if (inlinep & 2)
 	error_at (declspecs->locations[ds_constexpr],
-		  "cannot declare %<::main%> to be %<constexpr%>");
+		  "cannot declare %<::main%> to be %qs", "constexpr");
+      if (inlinep & 8)
+	error_at (declspecs->locations[ds_consteval],
+		  "cannot declare %<::main%> to be %qs", "consteval");
       if (!publicp)
 	error_at (location, "cannot declare %<::main%> to be static");
       inlinep = 0;
@@ -9428,6 +9459,11 @@ grokfndecl (tree ctype,
     }
   if (inlinep & 2)
     DECL_DECLARED_CONSTEXPR_P (decl) = true;
+  else if (inlinep & 8)
+    {
+      DECL_DECLARED_CONSTEXPR_P (decl) = true;
+      SET_DECL_IMMEDIATE_FUNCTION_P (decl);
+    }
 
   // If the concept declaration specifier was found, check
   // that the declaration satisfies the necessary requirements.
@@ -10786,6 +10822,7 @@ grokdeclarator (const cp_declarator *dec
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
+  bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
   tree reqs = NULL_TREE;
@@ -11058,17 +11095,31 @@ grokdeclarator (const cp_declarator *dec
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
+  if (consteval_p && constexpr_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+		"both %qs and %qs specified", "constexpr", "consteval");
+      return error_mark_node;
+    }
+
   if (concept_p && typedef_p)
     {
       error_at (declspecs->locations[ds_concept],
-		"%<concept%> cannot appear in a typedef declaration");
+		"%qs cannot appear in a typedef declaration", "concept");
       return error_mark_node;
     }
 
   if (constexpr_p && typedef_p)
     {
       error_at (declspecs->locations[ds_constexpr],
-		"%<constexpr%> cannot appear in a typedef declaration");
+		"%qs cannot appear in a typedef declaration", "constexpr");
+      return error_mark_node;
+    }
+
+  if (consteval_p && typedef_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+		"%qs cannot appear in a typedef declaration", "consteval");
       return error_mark_node;
     }
 
@@ -11474,21 +11525,31 @@ grokdeclarator (const cp_declarator *dec
 
       /* Function parameters cannot be concept. */
       if (concept_p)
-	error_at (declspecs->locations[ds_concept],
-		  "a parameter cannot be declared %<concept%>");
+	{
+	  error_at (declspecs->locations[ds_concept],
+		    "a parameter cannot be declared %qs", "concept");
+	  concept_p = 0;
+	  constexpr_p = 0;
+	}
       /* Function parameters cannot be constexpr.  If we saw one, moan
          and pretend it wasn't there.  */
       else if (constexpr_p)
         {
           error_at (declspecs->locations[ds_constexpr],
-		    "a parameter cannot be declared %<constexpr%>");
+		    "a parameter cannot be declared %qs", "constexpr");
           constexpr_p = 0;
         }
-      else if (constinit_p)
+      if (constinit_p)
 	{
 	  error_at (declspecs->locations[ds_constinit],
-		    "a parameter cannot be declared %<constinit%>");
-	  constexpr_p = 0;
+		    "a parameter cannot be declared %qs", "constinit");
+	  constinit_p = 0;
+	}
+      if (consteval_p)
+	{
+	  error_at (declspecs->locations[ds_consteval],
+		    "a parameter cannot be declared %qs", "consteval");
+	  consteval_p = 0;
 	}
     }
 
@@ -11511,9 +11572,12 @@ grokdeclarator (const cp_declarator *dec
       if (typedef_p)
 	error_at (declspecs->locations[ds_typedef],
 		  "structured binding declaration cannot be %qs", "typedef");
-      if (constexpr_p)
+      if (constexpr_p && !concept_p)
 	error_at (declspecs->locations[ds_constexpr], "structured "
 		  "binding declaration cannot be %qs", "constexpr");
+      if (consteval_p)
+	error_at (declspecs->locations[ds_consteval], "structured "
+		  "binding declaration cannot be %qs", "consteval");
       if (thread_p && cxx_dialect < cxx2a)
 	pedwarn (declspecs->locations[ds_thread], 0,
 		 "structured binding declaration can be %qs only in "
@@ -11573,6 +11637,7 @@ grokdeclarator (const cp_declarator *dec
       inlinep = 0;
       typedef_p = 0;
       constexpr_p = 0;
+      consteval_p = 0;
       concept_p = 0;
       if (storage_class != sc_static)
 	{
@@ -12967,7 +13032,7 @@ grokdeclarator (const cp_declarator *dec
                 if (concept_p)
                   {
                     error_at (declspecs->locations[ds_concept],
-			      "a destructor cannot be %<concept%>");
+			      "a destructor cannot be %qs", "concept");
                     return error_mark_node;
                   }
 		if (constexpr_p && cxx_dialect < cxx2a)
@@ -12977,6 +13042,12 @@ grokdeclarator (const cp_declarator *dec
 			      " with %<-std=c++2a%> or %<-std=gnu++2a%>");
 		    return error_mark_node;
 		  }
+		if (consteval_p)
+		  {
+		    error_at (declspecs->locations[ds_consteval],
+			      "a destructor cannot be %qs", "consteval");
+		    return error_mark_node;
+		  }
 	      }
 	    else if (sfk == sfk_constructor && friendp && !ctype)
 	      {
@@ -12998,6 +13069,14 @@ grokdeclarator (const cp_declarator *dec
 			  "a concept cannot be a member function");
 		concept_p = false;
 	      }
+	    else if (consteval_p
+		     && identifier_p (unqualified_id)
+		     && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+	      {
+		error_at (declspecs->locations[ds_consteval],
+			  "%qD cannot be %qs", unqualified_id, "consteval");
+		consteval_p = false;
+	      }
 
 	    if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
 	      {
@@ -13028,7 +13107,8 @@ grokdeclarator (const cp_declarator *dec
 			       reqs,
 			       virtualp, flags, memfn_quals, rqual, raises,
 			       friendp ? -1 : 0, friendp, publicp,
-                               inlinep | (2 * constexpr_p) | (4 * concept_p),
+			       inlinep | (2 * constexpr_p) | (4 * concept_p)
+				       | (8 * consteval_p),
 			       initialized == SD_DELETED, sfk,
 			       funcdef_flag, late_return_type_p,
 			       template_count, in_namespace,
@@ -13130,8 +13210,8 @@ grokdeclarator (const cp_declarator *dec
 		set_linkage_for_static_data_member (decl);
 		if (concept_p)
 		  error_at (declspecs->locations[ds_concept],
-			    "static data member %qE declared %<concept%>",
-			    unqualified_id);
+			    "static data member %qE declared %qs",
+			    unqualified_id, "concept");
 		else if (constexpr_p && !initialized)
 		  {
 		    error_at (DECL_SOURCE_LOCATION (decl),
@@ -13139,6 +13219,10 @@ grokdeclarator (const cp_declarator *dec
 			      "have an initializer", decl);
 		    constexpr_p = false;
 		  }
+		if (consteval_p)
+		  error_at (declspecs->locations[ds_consteval],
+			    "static data member %qE declared %qs",
+			    unqualified_id, "consteval");
 
 		if (inlinep)
 		  mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -13163,23 +13247,34 @@ grokdeclarator (const cp_declarator *dec
 	    else
 	      {
 		if (concept_p)
-		  error_at (declspecs->locations[ds_concept],
-			    "non-static data member %qE declared %<concept%>",
-			    unqualified_id);
-                else if (constexpr_p)
+		  {
+		    error_at (declspecs->locations[ds_concept],
+			      "non-static data member %qE declared %qs",
+			      unqualified_id, "concept");
+		    concept_p = false;
+		    constexpr_p = false;
+		  }
+		else if (constexpr_p)
 		  {
 		    error_at (declspecs->locations[ds_constexpr],
-			      "non-static data member %qE declared "
-			      "%<constexpr%>", unqualified_id);
+			      "non-static data member %qE declared %qs",
+			      unqualified_id, "constexpr");
 		    constexpr_p = false;
 		  }
-		else if (constinit_p)
+		if (constinit_p)
 		  {
 		    error_at (declspecs->locations[ds_constinit],
-			      "non-static data member %qE declared "
-			      "%<constinit%>", unqualified_id);
+			      "non-static data member %qE declared %qs",
+			      unqualified_id, "constinit");
 		    constinit_p = false;
 		  }
+		if (consteval_p)
+		  {
+		    error_at (declspecs->locations[ds_consteval],
+			      "non-static data member %qE declared %qs",
+			      unqualified_id, "consteval");
+		    consteval_p = false;
+		  }
 		decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type);
 		DECL_NONADDRESSABLE_P (decl) = bitfield;
 		if (bitfield && !unqualified_id)
@@ -13285,6 +13380,14 @@ grokdeclarator (const cp_declarator *dec
 		sfk = sfk_none;
 	      }
 	  }
+	if (consteval_p
+	    && identifier_p (unqualified_id)
+	    && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+	  {
+	    error_at (declspecs->locations[ds_consteval],
+		      "%qD cannot be %qs", unqualified_id, "consteval");
+	    consteval_p = false;
+	  }
 
 	/* Record whether the function is public.  */
 	publicp = (ctype != NULL_TREE
@@ -13295,7 +13398,8 @@ grokdeclarator (const cp_declarator *dec
                            reqs, virtualp, flags, memfn_quals, rqual, raises,
 			   1, friendp,
 			   publicp,
-                           inlinep | (2 * constexpr_p) | (4 * concept_p),
+			   inlinep | (2 * constexpr_p) | (4 * concept_p)
+				   | (8 * consteval_p),
 			   initialized == SD_DELETED,
                            sfk,
                            funcdef_flag,
@@ -13388,6 +13492,12 @@ grokdeclarator (const cp_declarator *dec
 		      "is not a definition", decl);
 	    constexpr_p = false;
 	  }
+	if (consteval_p)
+	  {
+	    error_at (DECL_SOURCE_LOCATION (decl),
+		      "a variable cannot be declared %<consteval%>");
+	    consteval_p = false;
+	  }
 
 	if (inlinep)
 	  mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -16696,7 +16806,7 @@ finish_function (bool inline_p)
     invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
 
   /* Perform delayed folding before NRV transformation.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_fold_function (fndecl);
 
   /* Set up the named return value optimization, if we can.  Candidate
@@ -16813,7 +16923,7 @@ finish_function (bool inline_p)
     do_warn_unused_parameter (fndecl);
 
   /* Genericize before inlining.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_genericize (fndecl);
 
   /* We're leaving the context of this function, so zap cfun.  It's still in
--- gcc/cp/constexpr.c.jj	2019-10-31 11:01:27.104215584 +0100
+++ gcc/cp/constexpr.c	2019-10-31 13:38:16.866178095 +0100
@@ -5711,6 +5711,16 @@ find_heap_var_refs (tree *tp, int *walk_
   return NULL_TREE;
 }
 
+/* Find immediate function decls in *TP if any.  */
+
+static tree
+find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
+    return *tp;
+  return NULL_TREE;
+}
+
 /* ALLOW_NON_CONSTANT is false if T is required to be a constant expression.
    STRICT has the same sense as for constant_value_1: true if we only allow
    conforming C++ constant expressions, or false if we want a constant value
@@ -5739,13 +5749,38 @@ cxx_eval_outermost_constant_expr (tree t
 
   tree type = initialized_type (t);
   tree r = t;
+  bool is_consteval = false;
   if (VOID_TYPE_P (type))
     {
       if (constexpr_dtor)
 	/* Used for destructors of array elements.  */
 	type = TREE_TYPE (object);
       else
-	return t;
+	{
+	  if (cxx_dialect < cxx2a)
+	    return t;
+	  if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+	    return t;
+	  /* Calls to immediate functions returning void need to be
+	     evaluated.  */
+	  tree fndecl = cp_get_callee_fndecl_nofold (t);
+	  if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
+	    return t;
+	  else
+	    is_consteval = true;
+	}
+    }
+  else if (cxx_dialect >= cxx2a
+	   && (TREE_CODE (t) == CALL_EXPR
+	       || TREE_CODE (t) == AGGR_INIT_EXPR
+	       || TREE_CODE (t) == TARGET_EXPR))
+    {
+      tree x = t;
+      if (TREE_CODE (x) == TARGET_EXPR)
+	x = TARGET_EXPR_INITIAL (x);
+      tree fndecl = cp_get_callee_fndecl_nofold (x);
+      if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+	is_consteval = true;
     }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
@@ -5846,6 +5881,25 @@ cxx_eval_outermost_constant_expr (tree t
 	  }
     }
 
+  /* Check that immediate invocation does not return an expression referencing
+     any immediate function decls.  They need to be allowed while parsing
+     immediate functions, but can't leak outside of them.  */
+  if (is_consteval
+      && t != r
+      && (current_function_decl == NULL_TREE
+	  || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    if (tree immediate_fndecl
+	= cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
+					   NULL))
+    {
+      if (!allow_non_constant && !non_constant_p)
+	error_at (cp_expr_loc_or_input_loc (t),
+		  "immediate evaluation returns address of immediate "
+		  "function %qD", immediate_fndecl);
+      r = t;
+      non_constant_p = true;
+    }
+
   /* Technically we should check this for all subexpressions, but that
      runs into problems with our internal representation of pointer
      subtraction and the 5.19 rules are still in flux.  */
@@ -6086,7 +6140,8 @@ clear_cv_and_fold_caches (bool sat /*= t
 
 static tree
 fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
-				  bool manifestly_const_eval)
+				  bool manifestly_const_eval,
+				  tree object)
 {
   gcc_assert (processing_template_decl);
 
@@ -6107,7 +6162,7 @@ fold_non_dependent_expr_template (tree t
 
       tree r = cxx_eval_outermost_constant_expr (t, true, true,
 						 manifestly_const_eval,
-						 false, NULL_TREE);
+						 false, object);
       /* cp_tree_equal looks through NOPs, so allow them.  */
       gcc_checking_assert (r == t
 			   || CONVERT_EXPR_P (t)
@@ -6143,16 +6198,17 @@ fold_non_dependent_expr_template (tree t
 tree
 fold_non_dependent_expr (tree t,
 			 tsubst_flags_t complain /* = tf_warning_or_error */,
-			 bool manifestly_const_eval /* = false */)
+			 bool manifestly_const_eval /* = false */,
+			 tree object /* = NULL_TREE */)
 {
   if (t == NULL_TREE)
     return NULL_TREE;
 
   if (processing_template_decl)
     return fold_non_dependent_expr_template (t, complain,
-					     manifestly_const_eval);
+					     manifestly_const_eval, object);
 
-  return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
+  return maybe_constant_value (t, object, manifestly_const_eval);
 }
 
 
@@ -6169,7 +6225,7 @@ fold_non_dependent_init (tree t,
   if (processing_template_decl)
     {
       t = fold_non_dependent_expr_template (t, complain,
-					    manifestly_const_eval);
+					    manifestly_const_eval, NULL_TREE);
       /* maybe_constant_init does this stripping, so do it here too.  */
       if (TREE_CODE (t) == TARGET_EXPR)
 	{
--- gcc/cp/method.c.jj	2019-10-24 14:46:35.198747738 +0200
+++ gcc/cp/method.c	2019-10-31 13:38:16.866178095 +0100
@@ -2228,8 +2228,9 @@ defaulted_late_check (tree fn)
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
 	{
 	  error ("explicitly defaulted function %q+D cannot be declared "
-		 "%qs because the implicit declaration is not %qs:",
-		 fn, "constexpr", "constexpr");
+		 "%qs because the implicit declaration is not %qs:", fn,
+		 DECL_IMMEDIATE_FUNCTION_P (fn) ? "consteval" : "constexpr",
+		 "constexpr");
 	  explain_implicit_non_constexpr (fn);
 	}
       DECL_DECLARED_CONSTEXPR_P (fn) = false;
--- gcc/cp/lambda.c.jj	2019-10-31 08:08:43.028784043 +0100
+++ gcc/cp/lambda.c	2019-10-31 13:38:16.866178095 +0100
@@ -1194,6 +1194,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = build_this_parm (fn, fntype, TYPE_QUAL_CONST);
 
   if (nested_def)
@@ -1226,6 +1229,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = fn_args;
   for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
--- gcc/cp/init.c.jj	2019-10-31 11:01:27.000000000 +0100
+++ gcc/cp/init.c	2019-10-31 13:53:46.041886286 +0100
@@ -348,14 +348,12 @@ build_value_init (tree type, tsubst_flag
   gcc_assert (!processing_template_decl
 	      || (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE));
 
-  if (CLASS_TYPE_P (type)
-      && type_build_ctor_call (type))
+  if (CLASS_TYPE_P (type) && type_build_ctor_call (type))
     {
-      tree ctor =
-	 build_special_member_call (NULL_TREE, complete_ctor_identifier,
-				    NULL, type, LOOKUP_NORMAL,
-				    complain);
-      if (ctor == error_mark_node)
+      tree ctor
+	= build_special_member_call (NULL_TREE, complete_ctor_identifier,
+				     NULL, type, LOOKUP_NORMAL, complain);
+      if (ctor == error_mark_node || TREE_CONSTANT (ctor))
 	return ctor;
       tree fn = NULL_TREE;
       if (TREE_CODE (ctor) == CALL_EXPR)
--- gcc/testsuite/g++.dg/cpp2a/consteval1.C.jj	2019-10-31 13:38:16.866178095 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval1.C	2019-10-31 13:38:16.866178095 +0100
@@ -0,0 +1,37 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+extern "C" void abort ();
+constexpr int f0 (int n) { return n; }
+consteval int f1 (int n) { return f0 (n) * n; }
+consteval int f2 (int n) { return f1 (n); }
+consteval bool f3 () { return std::is_constant_evaluated (); }
+struct S { constexpr S (int x) : s (x) {} consteval int m1 (int n) const; int s; };
+consteval int
+S::m1 (int n) const
+{
+  n += s;
+  return n;
+}
+
+constexpr int a = 2;
+int b = f1 (a);
+int c = f2 (f1 (a));
+bool d = f3 ();
+constexpr S e = 41;
+int f = e.m1 (1);
+
+int
+main ()
+{
+  if (b != 4 || c != 16 || !d || f != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval2.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval2.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+consteval int baz (int (*fn) () = bar ()) { return fn (); }
+constexpr int a = baz ();
+static_assert (a == 42);
+int b = baz ();
+
+int
+main ()
+{
+  if (b != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval3.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,63 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { S () : a (0), b (1) {} int a, b; };
+int f1 ();		// { dg-message "previous declaration 'int f1\\(\\)'" }
+consteval int f1 ();	// { dg-error "redeclaration 'consteval int f1\\(\\)' differs in 'consteval' from previous declaration" }
+consteval int f2 ();	// { dg-message "previous declaration 'consteval int f2\\(\\)'" }
+int f2 ();		// { dg-error "redeclaration 'int f2\\(\\)' differs in 'consteval' from previous declaration" }
+constexpr int f3 ();	// { dg-message "previous declaration 'constexpr int f3\\(\\)'" }
+consteval int f3 ();	// { dg-error "redeclaration 'consteval int f3\\(\\)' differs in 'consteval' from previous declaration" }
+consteval int f4 ();	// { dg-message "previous declaration 'consteval int f4\\(\\)'" }
+constexpr int f4 ();	// { dg-error "redeclaration 'constexpr int f4\\(\\)' differs in 'consteval' from previous declaration" }
+typedef consteval int cint;	// { dg-error "'consteval' cannot appear in a typedef declaration" }
+consteval struct T { int i; };	// { dg-error "'consteval' cannot be used for type declarations" }
+consteval int a = 5;	// { dg-error "a variable cannot be declared 'consteval'" }
+consteval auto [ b, c ] = S ();		// { dg-error "structured binding declaration cannot be 'consteval'" }
+int f5 (consteval int x) { return x; }	// { dg-error "a parameter cannot be declared 'consteval'" }
+consteval int f6 (int x) { return x; }
+int d = 6;		// { dg-message "'int d' is not const" }
+int e = f6 (d);		// { dg-error "the value of 'd' is not usable in a constant expression" }
+constexpr int f7 (int x) { return f6 (x); }	// { dg-error "'x' is not a constant expression" }
+constexpr int f = f7 (5);	// { dg-error "" }
+				// { dg-message "in 'constexpr' expansion of" "" { target *-*-* } .-1 }
+using fnptr = int (int);
+fnptr *g = f6;		// { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+int f8 (fnptr *);
+int h = f8 (f6);	// { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+consteval constexpr int f9 () { return 0; }	// { dg-error "both 'constexpr' and 'consteval' specified" }
+constexpr consteval int f10 () { return 0; }	// { dg-error "both 'constexpr' and 'consteval' specified" }
+consteval consteval int f11 () { return 0; }	// { dg-error "duplicate 'consteval'" }
+struct U { consteval ~U () {} };	// { dg-error "a destructor cannot be 'consteval'" }
+struct V { consteval int v = 5; };	// { dg-error "non-static data member 'v' declared 'consteval'" }
+struct W { consteval static int w; };	// { dg-error "static data member 'w' declared 'consteval'" }
+int i = sizeof (&f6);			// { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+using j = decltype (&f6);		// { dg-error "taking address of an immediate function 'consteval int f6\\(int\\)'" }
+int k = sizeof (f6 (d));		// { dg-error "the value of 'd' is not usable in a constant expression" }
+using l = decltype (f6 (d));		// { dg-error "the value of 'd' is not usable in a constant expression" }
+bool m = noexcept (f6 (d));		// { dg-error "the value of 'd' is not usable in a constant expression" }
+namespace std {
+using size_t = decltype (sizeof (0));
+}
+consteval void* operator new (std::size_t);	// { dg-error "'operator new' cannot be 'consteval'" }
+consteval void operator delete (void *, std::size_t) noexcept;	// { dg-error "'operator delete' cannot be 'consteval'" }
+consteval void operator delete[] (void *) noexcept;	// { dg-error "'operator delete \\\[\\\]' cannot be 'consteval'" }
+struct X {
+  static consteval void* operator new (std::size_t);	// { dg-error "'operator new' cannot be 'consteval'" }
+  static consteval void operator delete (void *, std::size_t) noexcept;	// { dg-error "'operator delete' cannot be 'consteval'" }
+  consteval static void operator delete[] (void *) noexcept;	// { dg-error "'operator delete \\\[\\\]' cannot be 'consteval'" }
+};
+consteval int main () { return 0; }	// { dg-error "cannot declare '::main' to be 'consteval'" }
+struct A { A (); int a; };		// { dg-message "defaulted constructor calls non-'constexpr' 'A::A\\(\\)'" }
+struct B { constexpr B () : b (0) {} int b; };
+struct C { A a; consteval C () = default; };	// { dg-error "explicitly defaulted function 'consteval C::C\\(\\)' cannot be declared 'consteval' because the implicit declaration is not 'constexpr'" }
+struct D { B b; consteval D () = default; };
+template <class T> consteval T f12 (T x) { return x; }
+template consteval float f12 (float x); // { dg-error "explicit instantiation shall not use 'consteval' specifier" }
+consteval int
+f13 (int x)
+{
+  static int a = 5;		// { dg-error "'a' declared 'static' in 'consteval' function" }
+  thread_local int b = 6;	// { dg-error "'b' declared 'thread_local' in 'consteval' function" }
+  return x;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval4.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval4.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,29 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int
+main ()
+{
+  constexpr int a = 5;
+  auto b = [] (int n) consteval { return n + a + std::is_constant_evaluated (); };
+  int c = b (4);
+  if (c != 10)
+    abort ();
+  auto d = [] () consteval { return a + std::is_constant_evaluated (); };
+  int e = d ();
+  if (e != 6)
+    abort ();
+  constexpr int f = d ();
+  if (f != 6)
+    abort ();
+  static_assert (d () == 6);
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval5.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval5.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,42 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+extern "C" void abort ();
+template <int N>
+constexpr int f0 (int n) { return n + N; }
+template <int N>
+consteval int f1 (int n) { return f0<N> (n) * n + N; }
+template <int N>
+consteval int f2 (int n) { return f1<N> (n); }
+template <int N>
+consteval bool f3 () { return std::is_constant_evaluated () + N; }
+struct S { constexpr S (int x) : s (x) {} template <int N> consteval int m1 (int n) const; int s; };
+template <int N>
+consteval int
+S::m1 (int n) const
+{
+  n += s + N;
+  return n;
+}
+
+constexpr int a = 2;
+int b = f1<0> (a);
+int c = f2<0> (f1<0> (a));
+bool d = f3<0> ();
+constexpr S e = 41;
+int f = e.m1<0> (1);
+
+int
+main ()
+{
+  if (b != 4 || c != 16 || !d || f != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval6.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval6.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct A {
+  constexpr A () {}
+  A (A const&) = delete;	// { dg-message "declared here" }
+};
+
+template<typename T>
+constexpr void
+foo ()
+{
+  T t;
+  T u = t;
+}
+
+template<typename T>
+consteval void
+bar ()
+{
+  T t;
+  T u = t;	// { dg-error "use of deleted function" }
+}
+
+using B = decltype (foo<A> ());
+using C = decltype (bar<A> ());	// { dg-message "required from here" }
--- gcc/testsuite/g++.dg/cpp2a/consteval7.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval7.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+constexpr auto a = bar ();	// { dg-error "immediate evaluation returns address of immediate function 'consteval int foo\\(\\)'" }
+struct S { int b; int (*c) (); };
+consteval S baz () { return { 5, foo }; }
+consteval int qux () { S s = baz (); return s.b + s.c (); }
+consteval int quux () { constexpr S s = baz (); return s.b + s.c (); }
+constexpr auto d = baz ();	// { dg-error "immediate evaluation returns address of immediate function 'consteval int foo\\(\\)'" }
+constexpr auto e = qux ();
+constexpr auto f = quux ();
--- gcc/testsuite/g++.dg/cpp2a/consteval8.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval8.C	2019-10-31 14:02:44.191604423 +0100
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+S d = 25;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  S b = 12;
+  c.a += b.a;
+  c.b += b.b;
+  S e[2];
+  S f[2] = { 1, 2 };
+  return S ().a + e[1].a + f[0].b;
+}
+
+constexpr S g;
+constexpr S h = 42;
+constexpr S i[2];
+constexpr S j[2] = { 3, 4 };
+static_assert (g.a == 2 && g.b == 3);
+static_assert (h.a == 43 && h.b == 41);
+static_assert (i[0].a == 2 && i[0].b == 3 && i[1].a == 2 && i[1].b == 3);
+static_assert (j[0].a == 4 && j[0].b == 2 && j[1].a == 5 && j[1].b == 3);
--- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval9.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,31 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar (int i) { if (i != 1) throw 1; return 0; }	// { dg-error "is not a constant expression" }
+
+template <int N>
+void foo ()
+{
+  int a = bar (N);
+}
+
+template <int N>
+void qux ()
+{
+  int a = bar (N);	// { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" }
+}
+
+template <int N>
+void quux ()
+{
+  int a = bar (5);	// { dg-message "in 'constexpr' expansion of 'bar\\(5\\)'" }
+}
+
+void
+baz ()
+{
+  foo<1> ();
+  qux<2> ();
+}
+
+int a = bar (2);	// { dg-message "in 'constexpr' expansion of 'bar\\(2\\)'" }
--- gcc/testsuite/g++.dg/cpp2a/consteval10.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval10.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,3 @@
+// { dg-do compile }
+
+consteval int bar (void) { return 0; }	// { dg-error "'consteval' does not name a type" "" { target c++17_down } }
--- gcc/testsuite/g++.dg/cpp2a/consteval11.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval11.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,140 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar (int i) { if (i != 1) throw 1; return 0; }	// { dg-error "is not a constant expression" }
+
+constexpr int a = bar (1);
+constexpr int b = bar (2);		// { dg-message "in 'constexpr' expansion of" }
+constexpr int c = 0 ? bar (3) : 1;	// { dg-message "in 'constexpr' expansion of" }
+const int d = bar (4);			// { dg-message "in 'constexpr' expansion of" }
+const int e = 0 ? bar (5) : 1;		// { dg-message "in 'constexpr' expansion of" }
+int f = bar (1);
+int g = bar (6);			// { dg-message "in 'constexpr' expansion of" }
+int h = 0 ? bar (7) : 1;		// { dg-message "in 'constexpr' expansion of" }
+
+void
+foo ()
+{
+  constexpr int a = bar (1);
+  constexpr int b = bar (2);		// { dg-message "in 'constexpr' expansion of" }
+  constexpr int c = 0 ? bar (3) : 1;	// { dg-message "in 'constexpr' expansion of" }
+  const int d = bar (4);		// { dg-message "in 'constexpr' expansion of" }
+  const int e = 0 ? bar (5) : 1;	// { dg-message "in 'constexpr' expansion of" }
+  int f = bar (1);
+  int g = bar (6);			// { dg-message "in 'constexpr' expansion of" }
+  int h = 0 ? bar (7) : 1;		// { dg-message "in 'constexpr' expansion of" }
+  h += 0 ? bar (8) : 1;			// { dg-message "in 'constexpr' expansion of" }
+  if (0)
+    bar (9);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (10);				// { dg-message "in 'constexpr' expansion of" }
+  if (1)
+    bar (11);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (12);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (0)
+    bar (13);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (14);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (1)
+    bar (15);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (16);				// { dg-message "in 'constexpr' expansion of" }
+}
+
+consteval int
+baz ()
+{
+  constexpr int a = bar (1);
+  constexpr int b = bar (2);		// { dg-message "in 'constexpr' expansion of" }
+  constexpr int c = 0 ? bar (3) : 1;
+  const int d = bar (4);
+  const int e = 0 ? bar (5) : 1;
+  int f = bar (1);
+  int g = bar (6);
+  int h = 0 ? bar (7) : 1;
+  h += 0 ? bar (8) : 1;
+  if (0)
+    bar (9);
+  else
+    bar (10);
+  if (1)
+    bar (11);
+  else
+    bar (12);
+  if constexpr (0)
+    bar (13);
+  else
+    bar (14);
+  if constexpr (1)
+    bar (15);
+  else
+    bar (16);
+  return 0;
+}
+
+template <typename T>
+void
+qux ()
+{
+  if (0)
+    bar (2);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (3);				// { dg-message "in 'constexpr' expansion of" }
+  if (1)
+    bar (4);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (5);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (0)
+    bar (6);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (7);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (1)
+    bar (8);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar (9);				// { dg-message "in 'constexpr' expansion of" }
+  if (0)
+    bar ((T) 2);
+  else
+    bar ((T) 3);
+  if (1)
+    bar ((T) 4);
+  else
+    bar ((T) 5);
+  if constexpr (0)
+    bar ((T) 6);
+  else
+    bar ((T) 7);
+  if constexpr (1)
+    bar ((T) 8);
+  else
+    bar ((T) 9);
+}
+
+template <typename T>
+void
+quux ()
+{
+  if (0)
+    bar ((T) 2);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar ((T) 3);				// { dg-message "in 'constexpr' expansion of" }
+  if (1)
+    bar ((T) 4);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar ((T) 5);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (0)
+    bar ((T) 6);
+  else
+    bar ((T) 7);				// { dg-message "in 'constexpr' expansion of" }
+  if constexpr (1)
+    bar ((T) 8);				// { dg-message "in 'constexpr' expansion of" }
+  else
+    bar ((T) 9);
+}
+
+void
+corge ()
+{
+  quux <int> ();
+}
--- gcc/testsuite/g++.dg/ext/consteval1.C.jj	2019-10-31 13:38:16.867178080 +0100
+++ gcc/testsuite/g++.dg/ext/consteval1.C	2019-10-31 13:38:16.867178080 +0100
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo (int x) { return x; }
+int d = 6;			// { dg-message "'int d' is not const" }
+bool e = __builtin_has_attribute (foo (d), packed);	// { dg-error "the value of 'd' is not usable in a constant expression" }
--- gcc/testsuite/g++.dg/cpp2a/consteval12.C.jj	2019-10-31 15:08:06.339252438 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval12.C	2019-10-31 15:44:07.417047230 +0100
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+   auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+   constexpr auto e = qux ();
+   static_assert (e == 42);
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval13.C.jj	2019-10-31 15:08:58.952443391 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval13.C	2019-10-31 15:43:43.438415168 +0100
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+   auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+   constexpr auto c = qux (baz);	// { dg-error "taking address of an immediate function" }
+   constexpr auto d = qux (bar);	// { dg-error "taking address of an immediate function" }
+   static_assert (c == 1);
+   static_assert (d == 42);
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval14.C.jj	2019-10-31 15:09:49.998658432 +0100
+++ gcc/testsuite/g++.dg/cpp2a/consteval14.C	2019-10-31 15:12:11.170487592 +0100
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+
+template <int N>
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  S b = 12;
+  c.a += b.a;
+  c.b += b.b;
+  S e[2];
+  S f[2] = { 1, 2 };
+  const S g;
+  c.a += g.a;
+  c.b += g.b;
+  const S h = 12;
+  c.a += h.a;
+  c.b += h.b;
+  const S i[2];
+  const S j[2] = { 1, 2 };
+  return S ().a + e[1].a + f[0].b + i[0].a + j[1].b;
+}
+
+int x = foo <2> ();


	Jakub



More information about the Gcc-patches mailing list