diff mbox series

[C++] Implement P1073R3: Immediate functions (PR c++/88335)

Message ID 20191015170442.GH2116@tucnak
State New
Headers show
Series [C++] Implement P1073R3: Immediate functions (PR c++/88335) | expand

Commit Message

Jakub Jelinek Oct. 15, 2019, 5:04 p.m. UTC
Hi!

The following patch implements P1073R3, i.e. consteval, except that
virtual consteval is not supported (I think support for that would need to
include the consteval virtual methods at the end of the binfo structures
after all non-consteval virtual methods, but make sure we don't actually
emit those in the actual virtual tables etc.).

Unlike the previous implementation, this doesn't invoke consteval function
already during parsing, but later on, so there aren't issues with say
consteval constructors or consteval in default arguments.
Initially I thought the best spot to do that would be during cp_fold, but
that isn't called e.g. on template function bodies before instantiation,
or on the expressions from unevaluated contexts, so I had to add a function
to walk trees and evaluate consteval function calls found in there.
Furthermore, cp_fold isn't called just during cp_fold_function, but also
during fold_for_warn etc., so some consteval functions might be evaluated
multiple times, which can be a problem that if there are errors, they might
be emitted multiple times.

If you think it is worth avoiding the tree walk for -std=c++2a for the
finish_function of non-templates, perhaps it could be done during
cp_genericize too.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2019-10-15  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.
	(cxx_eval_consteval): Declare.
	* 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_has_attribute_expression): Call cxx_eval_consteval.
	(cp_parser_lambda_declarator_opt): Handle ds_consteval.
	(cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
	(cp_parser_explicit_instantiation): Diagnose explicit instantiation
	with consteval specifier.
	(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.
	* 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.
	(finish_decltype_type): Call cxx_eval_consteval.
	* 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.
	(check_initializer): Call cxx_eval_consteval.
	(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.
	(finish_function): Call cxx_eval_consteval for non-immediate functions.
	* constexpr.c (struct constexpr_global_ctx): Add in_consteval field,
	initialize it in the constructor.
	(cxx_eval_call_expression): When encountering immediate function call
	outside of in_consteval and outside of immediate function, call
	cxx_constant_value.
	(find_immediate_fndecl): New function.
	(cxx_eval_outermost_constant_expr): Allow consteval calls returning
	void.  Set global_ctx.in_consteval.  Diagnose returning address of
	immediate function from in_consteval evaluation.
	(fold_non_dependent_expr_template): Add forward declaration.  Add
	allow_non_constant argument and pass it through to
	cxx_eval_outermost_constant_expr.
	(cxx_eval_consteval_r, cxx_eval_consteval): New functions.
	(fold_non_dependent_expr, fold_non_dependent_init): Adjust
	fold_non_dependent_expr_template callers.
	* method.c (defaulted_late_check): Adjust diagnostics for consteval.
	* except.c (finish_noexcept_expr): Call cxx_eval_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.
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/ext/consteval1.C: New test.


	Jakub

Comments

Jason Merrill Oct. 21, 2019, 5:59 p.m. UTC | #1
On 10/15/19 1:04 PM, Jakub Jelinek wrote:
> Hi!
> 
> The following patch implements P1073R3, i.e. consteval, except that
> virtual consteval is not supported (I think support for that would need to
> include the consteval virtual methods at the end of the binfo structures
> after all non-consteval virtual methods, but make sure we don't actually
> emit those in the actual virtual tables etc.).

Perhaps we should bypass the existing virtual function call mechanism 
for consteval, and instead find the complete object directly and call 
non-virtually.

> Unlike the previous implementation, this doesn't invoke consteval function
> already during parsing, but later on, so there aren't issues with say
> consteval constructors or consteval in default arguments.

Right, we can't immediately evaluate a class prvalue before we know what 
object it's initializing.

> Initially I thought the best spot to do that would be during cp_fold, but
> that isn't called e.g. on template function bodies before instantiation,
> or on the expressions from unevaluated contexts, so I had to add a function
> to walk trees and evaluate consteval function calls found in there.
> Furthermore, cp_fold isn't called just during cp_fold_function, but also
> during fold_for_warn etc., so some consteval functions might be evaluated
> multiple times, which can be a problem that if there are errors, they might
> be emitted multiple times.

I agree that cp_fold isn't the right place, since it does lowering for 
GCC internals, and consteval expansion is part of the language 
semantics.  So it should happen before constexpr body saving, as in your 
patch.

It seems like we want a finish_full_expression, and do consteval folding 
there (and not from finish_function).

Jason
Jakub Jelinek Oct. 21, 2019, 6:49 p.m. UTC | #2
On Mon, Oct 21, 2019 at 01:59:38PM -0400, Jason Merrill wrote:
> I agree that cp_fold isn't the right place, since it does lowering for GCC
> internals, and consteval expansion is part of the language semantics.  So it
> should happen before constexpr body saving, as in your patch.
> 
> It seems like we want a finish_full_expression, and do consteval folding
> there (and not from finish_function).

Do we have a reasonable place to catch the full expressions?

I mean, perhaps add_stmt if stmts_are_full_exprs_p () and the spots where
unevaluated operands are handled in the patch, but an immediate invocation
is also a full-expression but for the default argument expressions we don't
know if the calls will be immediate invocation or not. 
Aren't there hundreds of other places where full expressions are handled
though?  I mean, e.g. all expressions in OpenMP/OpenACC clauses, etc.?
If the consteval evaluation is performed from this finish_full_expression,
we'd also need to *walk_subtrees = 0; if we encounter already handled full
expressions in there (e.g. statement expressions etc.).

The finish_function was just an attempt to limit the number of places where
we need to call it to a minimum.

	Jakub
Jason Merrill Oct. 21, 2019, 8:44 p.m. UTC | #3
On 10/21/19 2:49 PM, Jakub Jelinek wrote:
> On Mon, Oct 21, 2019 at 01:59:38PM -0400, Jason Merrill wrote:
>> I agree that cp_fold isn't the right place, since it does lowering for GCC
>> internals, and consteval expansion is part of the language semantics.  So it
>> should happen before constexpr body saving, as in your patch.
>>
>> It seems like we want a finish_full_expression, and do consteval folding
>> there (and not from finish_function).
> 
> The finish_function was just an attempt to limit the number of places where
> we need to call it to a minimum.

Fair enough.  Maybe just a finish_unevaluated_operand then.

> +  if (init && TREE_STATIC (decl))
> +    init = cxx_eval_consteval (init);

Do we need this in addition to the cxx_constant_init in store_init_value?

Jason
Jakub Jelinek Oct. 22, 2019, 7:15 a.m. UTC | #4
On Mon, Oct 21, 2019 at 04:44:22PM -0400, Jason Merrill wrote:
> Perhaps we should bypass the existing virtual function call mechanism for
> consteval, and instead find the complete object directly and call
> non-virtually.

Maybe, but can that be done incrementally?

> > The finish_function was just an attempt to limit the number of places where
> > we need to call it to a minimum.
> 
> Fair enough.  Maybe just a finish_unevaluated_operand then.

Good idea, added.

Apparently there is one unevaluated operand I've missed, requires
expression, but I don't know anything about concepts.  Do we need to call
finish_unevaluated_operand from finish_requires_expr and tsubst_requires_expr
(the latter perhaps just if !processing_template_decl)?  Are the requires
params to be treated as non-constexpr entities (so e.g. passing them to a
consteval function would be an error)?

> > +  if (init && TREE_STATIC (decl))
> > +    init = cxx_eval_consteval (init);
> 
> Do we need this in addition to the cxx_constant_init in store_init_value?

cxx_constant_init indeed can handle immediate invocations when it encounters
them while evaluating the constant expression, like maybe_constant_value
etc.  cxx_constant_init is not called on all initializers though,
maybe_constant_value is called on others, and my understanding of consteval
is that immediate invocations need to be evaluated anywhere in the
expressions, not just in the subexpressions encountered during constexpr
evaluation.  In fact, the above with TREE_STATIC isn't enough, because
we perform cp_fold on non-TREE_STATIC initializers (maybe we shouldn't and
defer that to cp_fold_function?), it is needed also for non-TREE_STATIC
initializers, but even for TREE_STATIC, the first point is avoid evaluating
immediate invocations multiple times and second ensure they are evaluated
everywhere.  The waqy cxx_eval_consteval is written, it doesn't hurt if
it is called multiple times, because it replaces the immediate evaluations
with their constant values or void/zero constant (if errors were detected).

I've added a whole new testcase (consteval11.C) which covers
in 0 ? immediate_invocation : ... etc. and made the check_initializer
changes that were needed for that.  Am not 100% sure about the
diagnostics in consteval function when it is initializer of a constexpr
function, but I believe in that case it isn't treated as immediate
invocation, just normal call during constexpr processing.

Now, I'm afraid I have no idea what is the right behavior if immediate
invocations appear in discarded statements.  Guess we need testsuite
coverage for that too.

Here is the updated patch.

2019-10-22  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.
	(cxx_eval_consteval, finish_unevaluated_operand): Declare.
	* 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_has_attribute_expression): Call finish_unevaluated_operand.
	(cp_parser_lambda_declarator_opt): Handle ds_consteval.
	(cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
	(cp_parser_explicit_instantiation): Diagnose explicit instantiation
	with consteval specifier.
	(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.
	* 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.
	(finish_decltype_type): Call finish_unevaluated_operand.
	* 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.
	(check_initializer): Call cxx_eval_consteval.
	(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.
	(finish_function): Call cxx_eval_consteval for non-immediate functions.
	* constexpr.c (struct constexpr_global_ctx): Add in_consteval field,
	initialize it in the constructor.
	(cxx_eval_call_expression): When encountering immediate function call
	outside of in_consteval and outside of immediate function, call
	cxx_constant_value.
	(find_immediate_fndecl): New function.
	(cxx_eval_outermost_constant_expr): Allow consteval calls returning
	void.  Set global_ctx.in_consteval.  Diagnose returning address of
	immediate function from in_consteval evaluation.
	(fold_non_dependent_expr_template): Add forward declaration.  Add
	allow_non_constant argument and pass it through to
	cxx_eval_outermost_constant_expr.
	(cxx_eval_consteval_r, cxx_eval_consteval,
	finish_unevaluated_operand): New functions.
	(fold_non_dependent_expr, fold_non_dependent_init): Adjust
	fold_non_dependent_expr_template callers.
	* method.c (defaulted_late_check): Adjust diagnostics for consteval.
	* except.c (finish_noexcept_expr): Call finish_unevaluated_operand.
	* 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.
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/ext/consteval1.C: New test.

--- gcc/c-family/c-common.h.jj	2019-10-16 09:30:56.516124577 +0200
+++ gcc/c-family/c-common.h	2019-10-22 08:15:53.806775889 +0200
@@ -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-16 09:30:56.496124879 +0200
+++ gcc/c-family/c-common.c	2019-10-22 08:15:53.808775858 +0200
@@ -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-18 16:33:37.283060458 +0200
+++ gcc/cp/cp-tree.h	2019-10-22 08:15:53.810775827 +0200
@@ -2692,7 +2692,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.  */
 
@@ -3206,6 +3207,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.
@@ -5864,6 +5874,7 @@ enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7802,6 +7813,8 @@ extern tree fold_non_dependent_expr		(tr
 extern tree fold_non_dependent_init		(tree,
 						 tsubst_flags_t = tf_warning_or_error,
 						 bool = false);
+extern tree cxx_eval_consteval			(tree);
+extern tree finish_unevaluated_operand		(tree);
 extern tree fold_simple				(tree);
 extern bool reduced_constant_expression_p       (tree);
 extern bool is_instantiation_of_constexpr       (tree);
--- gcc/cp/parser.c.jj	2019-10-22 08:12:25.351981502 +0200
+++ gcc/cp/parser.c	2019-10-22 08:15:53.816775735 +0200
@@ -995,11 +995,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:
@@ -1827,7 +1829,8 @@ 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,
@@ -8579,7 +8582,10 @@ cp_parser_has_attribute_expression (cp_p
   /* If the type-id production did not work out, then we must be
      looking at an expression.  */
   if (!oper || oper == error_mark_node)
-    oper = cp_parser_assignment_expression (parser);
+    {
+      oper = cp_parser_assignment_expression (parser);
+      oper = finish_unevaluated_operand (oper);
+    }
 
   STRIP_ANY_LOCATION_WRAPPER (oper);
 
@@ -10997,6 +11003,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);
 
@@ -14057,6 +14066,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);
@@ -14174,7 +14188,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]);
 
@@ -17313,6 +17328,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);
@@ -29964,9 +29983,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-16 09:30:57.130115306 +0200
+++ gcc/cp/call.c	2019-10-22 08:15:53.817775719 +0200
@@ -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);
 
--- gcc/cp/error.c.jj	2019-10-18 00:16:09.848546235 +0200
+++ gcc/cp/error.c	2019-10-22 08:15:53.818775704 +0200
@@ -1648,7 +1648,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-16 09:30:57.598108240 +0200
+++ gcc/cp/semantics.c	2019-10-22 08:15:53.819775689 +0200
@@ -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)))))
@@ -9628,6 +9629,8 @@ finish_decltype_type (tree expr, bool id
       return error_mark_node;
     }
 
+  expr = finish_unevaluated_operand (expr);
+
   /* Depending on the resolution of DR 1172, we may later need to distinguish
      instantiation-dependent but not type-dependent expressions so that, say,
      A<decltype(sizeof(T))>::U doesn't require 'typename'.  */
--- gcc/cp/typeck.c.jj	2019-10-21 20:50:43.576509781 +0200
+++ gcc/cp/typeck.c	2019-10-22 08:15:53.819775689 +0200
@@ -1860,10 +1860,11 @@ cxx_alignof_expr (tree e, tsubst_flags_t
 tree
 cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
 {
+  e = finish_unevaluated_operand (e);
   if (op == SIZEOF_EXPR)
-    return cxx_sizeof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_sizeof_expr (e, complain ? tf_warning_or_error : tf_none);
   else
-    return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_alignof_expr (e, complain ? tf_warning_or_error : tf_none);
 }
 
 /*  Build a representation of an expression 'alignas(E).'  Return the
@@ -6177,6 +6178,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-21 20:50:42.196530881 +0200
+++ gcc/cp/decl.c	2019-10-22 08:39:35.282916570 +0200
@@ -1224,7 +1224,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))
@@ -1232,6 +1238,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]
@@ -1241,9 +1249,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;
@@ -5014,12 +5027,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)
@@ -5377,11 +5393,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)
@@ -6539,6 +6558,11 @@ check_initializer (tree decl, tree init,
     /* There is no way to make a variable-sized class type in GNU C++.  */
     gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
 
+  if (init
+      && (current_function_decl == NULL_TREE
+	  || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    init = cxx_eval_consteval (init);
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
     {
       int init_len = CONSTRUCTOR_NELTS (init);
@@ -9134,6 +9158,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);
@@ -9181,7 +9214,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;
@@ -9220,6 +9256,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.
@@ -10578,6 +10619,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;
@@ -10850,17 +10892,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;
     }
 
@@ -11266,21 +11322,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;
 	}
     }
 
@@ -11303,9 +11369,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 "
@@ -11365,6 +11434,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)
 	{
@@ -12759,7 +12829,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)
@@ -12769,6 +12839,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)
 	      {
@@ -12790,6 +12866,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)
 	      {
@@ -12820,7 +12904,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,
@@ -12922,8 +13007,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),
@@ -12931,6 +13016,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]);
@@ -12955,23 +13044,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)
@@ -13077,6 +13177,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
@@ -13087,7 +13195,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,
@@ -13180,6 +13289,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]);
@@ -16440,6 +16555,9 @@ finish_function (bool inline_p)
 	  || is_valid_constexpr_fn (fndecl, /*complain*/false))
 	 && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
 
+  if (!DECL_IMMEDIATE_FUNCTION_P (fndecl))
+    DECL_SAVED_TREE (fndecl) = cxx_eval_consteval (DECL_SAVED_TREE (fndecl));
+
   /* Save constexpr function body before it gets munged by
      the NRV transformation.   */
   maybe_save_function_definition (fndecl);
@@ -16449,7 +16567,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
@@ -16566,7 +16684,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-21 20:51:14.889031012 +0200
+++ gcc/cp/constexpr.c	2019-10-22 08:17:21.701424246 +0200
@@ -1022,8 +1022,10 @@ struct constexpr_global_ctx {
   /* Heap VAR_DECLs created during the evaluation of the outermost constant
      expression.  */
   auto_vec<tree, 16> heap_vars;
+  /* True if evaluating a call to consteval function.  */
+  bool in_consteval;
   /* Constructor.  */
-  constexpr_global_ctx () : constexpr_ops_count (0) {}
+  constexpr_global_ctx () : constexpr_ops_count (0), in_consteval (false) {}
 };
 
 /* The constexpr expansion context.  CALL is the current function
@@ -1663,6 +1665,20 @@ cxx_eval_call_expression (const constexp
 	    }
 	}
     }
+  else if (DECL_IMMEDIATE_FUNCTION_P (fun)
+	   && !ctx->global->in_consteval
+	   && (current_function_decl == NULL_TREE
+	       || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    {
+      tree c = cxx_constant_value (t, NULL_TREE);
+      if (c == t || c == error_mark_node)
+	{
+	  *non_constant_p = true;
+	  return t;
+	}
+      return cxx_eval_constant_expression (ctx, c, lval, non_constant_p,
+					   overflow_p);
+    }
   if (TREE_CODE (fun) != FUNCTION_DECL)
     {
       if (!ctx->quiet && !*non_constant_p)
@@ -5645,6 +5661,17 @@ 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
@@ -5679,7 +5706,26 @@ cxx_eval_outermost_constant_expr (tree t
 	/* 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
+	    global_ctx.in_consteval = true;
+	}
+    }
+  else if (cxx_dialect >= cxx2a
+	   && (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR))
+    {
+      tree fndecl = cp_get_callee_fndecl_nofold (t);
+      if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+	global_ctx.in_consteval = true;
     }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
@@ -5780,6 +5826,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 (global_ctx.in_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.  */
@@ -5869,6 +5934,71 @@ cxx_constant_dtor (tree t, tree decl)
   cxx_eval_outermost_constant_expr (t, false, true, true, true, decl);
 }
 
+static tree
+fold_non_dependent_expr_template (tree, tsubst_flags_t, bool, bool);
+
+/* Helper function for cxx_eval_consteval.  Find calls to immediate
+   functions in *TP and evaluate them.  */
+
+static tree
+cxx_eval_consteval_r (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
+    {
+      tree callee = cp_get_callee (*tp);
+      if (processing_template_decl
+	  && callee
+	  && TREE_CODE (callee) != FUNCTION_DECL
+	  && (TREE_TYPE (callee) == NULL_TREE
+	      || !INDIRECT_TYPE_P (TREE_TYPE (callee))))
+	return NULL_TREE;
+      callee = cp_get_fndecl_from_callee (callee, false);
+      if (callee && DECL_IMMEDIATE_FUNCTION_P (callee))
+	{
+	  if (processing_template_decl)
+	    fold_non_dependent_expr_template (*tp, tf_warning_or_error,
+					      /*allow_non_constant*/false,
+					      /*manifestly_const_eval=*/ true);
+	  else
+	    {
+	      int saved_errorcount = errorcount;
+	      tree t = cxx_constant_value (*tp, NULL_TREE);
+	      if (t != *tp)
+		*tp = t;
+	      else
+		{
+		  /* Error recovery, make sure we don't diagnose it multiple
+		     times.  */
+		  gcc_assert (errorcount > saved_errorcount);
+		  if (VOID_TYPE_P (TREE_TYPE (*tp)))
+		    *tp = void_node;
+		  else
+		    *tp = build_zero_cst (t);
+		}
+	    }
+	}
+    }
+  return NULL_TREE;
+}
+
+/* Evaluate calls to immediate functions in T.  */
+
+tree
+cxx_eval_consteval (tree t)
+{
+  if (cxx_dialect >= cxx2a)
+    cp_walk_tree_without_duplicates (&t, cxx_eval_consteval_r, NULL);
+  return t;
+}
+
+/* Finish an unevaluated operand T.  */
+
+tree
+finish_unevaluated_operand (tree t)
+{
+  return cxx_eval_consteval (t);
+}
+
 /* Helper routine for fold_simple function.  Either return simplified
    expression T, otherwise NULL_TREE.
    In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
@@ -6020,6 +6150,7 @@ clear_cv_and_fold_caches (bool sat /*= t
 
 static tree
 fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
+				  bool allow_non_constant,
 				  bool manifestly_const_eval)
 {
   gcc_assert (processing_template_decl);
@@ -6039,7 +6170,7 @@ fold_non_dependent_expr_template (tree t
 	  return t;
 	}
 
-      tree r = cxx_eval_outermost_constant_expr (t, true, true,
+      tree r = cxx_eval_outermost_constant_expr (t, allow_non_constant, true,
 						 manifestly_const_eval,
 						 false, NULL_TREE);
       /* cp_tree_equal looks through NOPs, so allow them.  */
@@ -6084,6 +6215,7 @@ fold_non_dependent_expr (tree t,
 
   if (processing_template_decl)
     return fold_non_dependent_expr_template (t, complain,
+					     /*allow_non_constant*/true,
 					     manifestly_const_eval);
 
   return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
@@ -6103,6 +6235,7 @@ fold_non_dependent_init (tree t,
   if (processing_template_decl)
     {
       t = fold_non_dependent_expr_template (t, complain,
+					    /*allow_non_constant*/true,
 					    manifestly_const_eval);
       /* maybe_constant_init does this stripping, so do it here too.  */
       if (TREE_CODE (t) == TARGET_EXPR)
--- gcc/cp/method.c.jj	2019-10-16 09:30:57.194114341 +0200
+++ gcc/cp/method.c	2019-10-22 08:15:53.822775643 +0200
@@ -2256,8 +2256,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/except.c.jj	2019-10-16 09:30:57.246113554 +0200
+++ gcc/cp/except.c	2019-10-22 08:15:53.822775643 +0200
@@ -1191,6 +1191,8 @@ finish_noexcept_expr (tree expr, tsubst_
   if (expr == error_mark_node)
     return error_mark_node;
 
+  expr = finish_unevaluated_operand (expr);
+
   if (processing_template_decl)
     return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
 
--- gcc/cp/lambda.c.jj	2019-10-18 00:16:10.010543831 +0200
+++ gcc/cp/lambda.c	2019-10-22 08:15:53.822775643 +0200
@@ -1188,6 +1188,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)
@@ -1220,6 +1223,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/testsuite/g++.dg/cpp2a/consteval1.C.jj	2019-10-22 08:15:53.822775643 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval1.C	2019-10-22 08:15:53.822775643 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval2.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C	2019-10-22 08:15:53.823775627 +0200
@@ -0,0 +1,62 @@
+// { 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 "" }
+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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval4.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval5.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval6.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval7.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval8.C	2019-10-22 08:15:53.823775627 +0200
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } int a, b; };
+S c;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  return S ().a;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj	2019-10-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval9.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval10.C	2019-10-22 08:15:53.823775627 +0200
@@ -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-22 08:28:04.724535848 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval11.C	2019-10-22 08:41:34.988076085 +0200
@@ -0,0 +1,58 @@
+// { 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" }
+}
+
+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);
+  return 0;
+}
--- gcc/testsuite/g++.dg/ext/consteval1.C.jj	2019-10-22 08:15:53.823775627 +0200
+++ gcc/testsuite/g++.dg/ext/consteval1.C	2019-10-22 08:15:53.823775627 +0200
@@ -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" }


	Jakub
Jason Merrill Oct. 22, 2019, 1:52 p.m. UTC | #5
On Tue, Oct 22, 2019 at 3:15 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Mon, Oct 21, 2019 at 04:44:22PM -0400, Jason Merrill wrote:
> > Perhaps we should bypass the existing virtual function call mechanism for
> > consteval, and instead find the complete object directly and call
> > non-virtually.
>
> Maybe, but can that be done incrementally?

Certainly.

> > > The finish_function was just an attempt to limit the number of places where
> > > we need to call it to a minimum.
> >
> > Fair enough.  Maybe just a finish_unevaluated_operand then.
>
> Good idea, added.
>
> Apparently there is one unevaluated operand I've missed, requires
> expression, but I don't know anything about concepts.  Do we need to call
> finish_unevaluated_operand from finish_requires_expr and tsubst_requires_expr

Sounds good.

> (the latter perhaps just if !processing_template_decl)?

I'd think we would want to be consistent with other immediate
invocations in template context.

> Are the requires params to be treated as non-constexpr entities (so e.g. passing them to a
> consteval function would be an error)?

That's an open question, but let's assume so for now.

> > > +  if (init && TREE_STATIC (decl))
> > > +    init = cxx_eval_consteval (init);
> >
> > Do we need this in addition to the cxx_constant_init in store_init_value?
>
> cxx_constant_init indeed can handle immediate invocations when it encounters
> them while evaluating the constant expression, like maybe_constant_value
> etc.  cxx_constant_init is not called on all initializers though,
> maybe_constant_value is called on others, and my understanding of consteval
> is that immediate invocations need to be evaluated anywhere in the
> expressions, not just in the subexpressions encountered during constexpr
> evaluation.

Good point.

> In fact, the above with TREE_STATIC isn't enough, because
> we perform cp_fold on non-TREE_STATIC initializers

Is that a problem?

> (maybe we shouldn't and defer that to cp_fold_function?)

I think it's done early now for the sake of constant evaluation later
in the function, but perhaps that's not necessary anymore.

> it is needed also for non-TREE_STATIC
> initializers, but even for TREE_STATIC, the first point is avoid evaluating
> immediate invocations multiple times and second ensure they are evaluated
> everywhere.  The way cxx_eval_consteval is written, it doesn't hurt if
> it is called multiple times, because it replaces the immediate evaluations
> with their constant values or void/zero constant (if errors were detected).
>
> I've added a whole new testcase (consteval11.C) which covers
> in 0 ? immediate_invocation : ... etc. and made the check_initializer
> changes that were needed for that.  Am not 100% sure about the
> diagnostics in consteval function when it is initializer of a constexpr
> function, but I believe in that case it isn't treated as immediate
> invocation, just normal call during constexpr processing.

> Now, I'm afraid I have no idea what is the right behavior if immediate
> invocations appear in discarded statements.  Guess we need testsuite
> coverage for that too.

Discarded statements aren't instantiated at all, so we shouldn't see
immediate invocations there.

Jason
Jason Merrill Oct. 22, 2019, 1:55 p.m. UTC | #6
On Mon, Oct 21, 2019 at 1:59 PM Jason Merrill <jason@redhat.com> wrote:
> On 10/15/19 1:04 PM, Jakub Jelinek wrote:

> > Unlike the previous implementation, this doesn't invoke consteval function
> > already during parsing, but later on, so there aren't issues with say
> > consteval constructors or consteval in default arguments.
>
> Right, we can't immediately evaluate a class prvalue before we know what
> object it's initializing.

Actually, I'm not sure about this.  There's no way to consistently
know what object is being initialized soon enough for the evaluation
to be immediate, so I think we need to always create a temporary for
immediate invocations of class type, so we could go ahead and do
immediate evaluation in build_cxx_call.  I think this also follows
from an immediate invocation being a full-expression.

Jason
Jakub Jelinek Oct. 22, 2019, 2:24 p.m. UTC | #7
On Tue, Oct 22, 2019 at 09:52:44AM -0400, Jason Merrill wrote:
> Sounds good.
> 
> > (the latter perhaps just if !processing_template_decl)?
> 
> I'd think we would want to be consistent with other immediate
> invocations in template context.

The other ones just call it regardless of processing_template_decl.
The reason for !processing_template_decl would be that otherwise
tsubst_requires_expr calls finish_requires_expr which would already call the
finish_unevaluated_operand.  Though, I'm afraid it is unclear to me
where to call finish_unevaluated_operand in tsubst_requires_expr,
as we need to call it on a tsubsted expression (it was already called
on the non-tsubsted one), but it looks like tsubst_requirement_body
returns error_mark_node both in cases where there is some substitution
failure diagnosed, or when there is some failure.  And we don't call
tsubst_requirement_body at all if tsubst_constraint_variables fails.

> > In fact, the above with TREE_STATIC isn't enough, because
> > we perform cp_fold on non-TREE_STATIC initializers
> 
> Is that a problem?

If we cxx_eval_consteval first, then it isn't a problem I guess at least
for the consteval stuff.  Though, e.g. the initializer could contain
in constexpr functions expressions that during constexpr evaluation would
need to be diagnosed and cp_fold would make that go away.  Say out of bounds
access to something that cp_fold happily folds away.

> > Now, I'm afraid I have no idea what is the right behavior if immediate
> > invocations appear in discarded statements.  Guess we need testsuite
> > coverage for that too.
> 
> Discarded statements aren't instantiated at all, so we shouldn't see
> immediate invocations there.

Ok.

	Jakub
Jakub Jelinek Oct. 22, 2019, 2:41 p.m. UTC | #8
On Tue, Oct 22, 2019 at 09:55:06AM -0400, Jason Merrill wrote:
> On Mon, Oct 21, 2019 at 1:59 PM Jason Merrill <jason@redhat.com> wrote:
> > On 10/15/19 1:04 PM, Jakub Jelinek wrote:
> 
> > > Unlike the previous implementation, this doesn't invoke consteval function
> > > already during parsing, but later on, so there aren't issues with say
> > > consteval constructors or consteval in default arguments.
> >
> > Right, we can't immediately evaluate a class prvalue before we know what
> > object it's initializing.
> 
> Actually, I'm not sure about this.  There's no way to consistently
> know what object is being initialized soon enough for the evaluation
> to be immediate, so I think we need to always create a temporary for
> immediate invocations of class type, so we could go ahead and do
> immediate evaluation in build_cxx_call.  I think this also follows
> from an immediate invocation being a full-expression.

So, do you prefer to do it the other way during build_cxx_call?

The issues that need to be resolved are the default arguments,
which from my understanding are not full expressions and thus for them we do
not know whether they will appear in immediate function context or not,
so would we need some global flag (in_default_argument?) and just don't
handle it in build_cxx_call if it is set, and then have something like
cxx_eval_consteval in the recent patch invoked on the default arguments
before adding it to function calls?

How would I create a temporary into which construct the var?
Wouldn't it affect also what constructors are invoked?  Say if some class
has consteval constructor with int argument and non-consteval copy
constructor:
struct S { consteval S (int x) : s (x) {} S (const S &); int s; };
should
void foo () { S s = 5; }
then invoke first the consteval ctor constructing some temporary and then
the copy constructor?

And last, wouldn't handling it in build_cxx_call already affect then
discarded statements?  The patch I posted today would most likely not
consteval evaluate much in discarded contexts, perhaps with the exception
of variable initializers.  But build_cxx_call is called even if
in_discarded_stmt, right?  Aren't some constant expressions evaluated even
in discarded statements though?
constexpr bool foo (int i) { if (i == 1) throw 1; return i == 0; }
template <typename T>
void
foo ()
{
  if constexpr (foo (2))
    {
      if constexpr (foo (1))
	;
    }
}
so, shouldn't immediate functions be called too?

	Jakub
Jason Merrill Oct. 22, 2019, 2:57 p.m. UTC | #9
On Tue, Oct 22, 2019 at 10:41 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Tue, Oct 22, 2019 at 09:55:06AM -0400, Jason Merrill wrote:
> > On Mon, Oct 21, 2019 at 1:59 PM Jason Merrill <jason@redhat.com> wrote:
> > > On 10/15/19 1:04 PM, Jakub Jelinek wrote:
> >
> > > > Unlike the previous implementation, this doesn't invoke consteval function
> > > > already during parsing, but later on, so there aren't issues with say
> > > > consteval constructors or consteval in default arguments.
> > >
> > > Right, we can't immediately evaluate a class prvalue before we know what
> > > object it's initializing.
> >
> > Actually, I'm not sure about this.  There's no way to consistently
> > know what object is being initialized soon enough for the evaluation
> > to be immediate, so I think we need to always create a temporary for
> > immediate invocations of class type, so we could go ahead and do
> > immediate evaluation in build_cxx_call.  I think this also follows
> > from an immediate invocation being a full-expression.
>
> So, do you prefer to do it the other way during build_cxx_call?

It seems more straightforward.

> The issues that need to be resolved are the default arguments,
> which from my understanding are not full expressions and thus for them we do
> not know whether they will appear in immediate function context or not,
> so would we need some global flag (in_default_argument?) and just don't
> handle it in build_cxx_call if it is set, and then have something like
> cxx_eval_consteval in the recent patch invoked on the default arguments
> before adding it to function calls?

It seems to me that an immediate invocation in a default argument is
not in immediate function context, so we can handle it normally.  The
only reason we need to handle immediate function context specially is
to allow uses of parameters of the immediate function in calls to
other immediate functions, and we can't refer to parameters in a
default argument anyway.

> How would I create a temporary into which construct the var?

The build_cplus_new in build_cxx_call creates a TARGET_EXPR,
evaluating that should be sufficient.  Note that you'll need to change
the condition there so that the decltype semantics don't apply to
immediate functions.

> Wouldn't it affect also what constructors are invoked?  Say if some class
> has consteval constructor with int argument and non-consteval copy
> constructor:
> struct S { consteval S (int x) : s (x) {} S (const S &); int s; };
> should
> void foo () { S s = 5; }
> then invoke first the consteval ctor constructing some temporary and then
> the copy constructor?

Yes, I think that follows.

> And last, wouldn't handling it in build_cxx_call already affect then
> discarded statements?  The patch I posted today would most likely not
> consteval evaluate much in discarded contexts, perhaps with the exception
> of variable initializers.  But build_cxx_call is called even if
> in_discarded_stmt, right?  Aren't some constant expressions evaluated even
> in discarded statements though?
> constexpr bool foo (int i) { if (i == 1) throw 1; return i == 0; }
> template <typename T>
> void
> foo ()
> {
>   if constexpr (foo (2))
>     {
>       if constexpr (foo (1))
>         ;
>     }
> }
> so, shouldn't immediate functions be called too?

Yes, true.  I wasn't thinking of non-dependent discarded statements.

Jason
Jakub Jelinek Oct. 22, 2019, 3:20 p.m. UTC | #10
On Tue, Oct 22, 2019 at 10:57:42AM -0400, Jason Merrill wrote:
> > So, do you prefer to do it the other way during build_cxx_call?
> 
> It seems more straightforward.

Ok.

> > The issues that need to be resolved are the default arguments,
> > which from my understanding are not full expressions and thus for them we do
> > not know whether they will appear in immediate function context or not,
> > so would we need some global flag (in_default_argument?) and just don't
> > handle it in build_cxx_call if it is set, and then have something like
> > cxx_eval_consteval in the recent patch invoked on the default arguments
> > before adding it to function calls?
> 
> It seems to me that an immediate invocation in a default argument is
> not in immediate function context, so we can handle it normally.  The
> only reason we need to handle immediate function context specially is
> to allow uses of parameters of the immediate function in calls to
> other immediate functions, and we can't refer to parameters in a
> default argument anyway.

Well, [expr.const]/(10.4) contains an example that requires it to work:
consteval int f() { return 42; }
consteval auto g() { return f; }
consteval int h(int (*p)() = g()) { return p(); }
constexpr int r = h(); // OK
constexpr auto e = g(); // ill-formed: a pointer to an immediate function is
			// not a permitted result of a constant expression
When parsing the g() expression as default argument, we don't know it will
be a default argument of a consteval function.  If g() is evaluated here
while parsing it, it would return address of consteval function, which is
invalid.

> > Wouldn't it affect also what constructors are invoked?  Say if some class
> > has consteval constructor with int argument and non-consteval copy
> > constructor:
> > struct S { consteval S (int x) : s (x) {} S (const S &); int s; };
> > should
> > void foo () { S s = 5; }
> > then invoke first the consteval ctor constructing some temporary and then
> > the copy constructor?
> 
> Yes, I think that follows.

But in that case whether the temporary is created or not is no longer an
implementation detail, so is it clear and can be clarified in the standard
that a temporary must be created, so that other implementations will handle
it the same?

> > And last, wouldn't handling it in build_cxx_call already affect then
> > discarded statements?  The patch I posted today would most likely not
> > consteval evaluate much in discarded contexts, perhaps with the exception
> > of variable initializers.  But build_cxx_call is called even if
> > in_discarded_stmt, right?  Aren't some constant expressions evaluated even
> > in discarded statements though?
> > constexpr bool foo (int i) { if (i == 1) throw 1; return i == 0; }
> > template <typename T>
> > void
> > foo ()
> > {
> >   if constexpr (foo (2))
> >     {
> >       if constexpr (foo (1))
> >         ;
> >     }
> > }
> > so, shouldn't immediate functions be called too?
> 
> Yes, true.  I wasn't thinking of non-dependent discarded statements.

Though, if we don't go the build_cxx_call route, we'd then need to
cxx_eval_consteval the discarded expressions before we overwrite them to
NULL_TREE.

	Jakub
Jason Merrill Oct. 22, 2019, 3:53 p.m. UTC | #11
On Tue, Oct 22, 2019 at 11:20 AM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Tue, Oct 22, 2019 at 10:57:42AM -0400, Jason Merrill wrote:
> > > So, do you prefer to do it the other way during build_cxx_call?
> >
> > It seems more straightforward.
>
> Ok.
>
> > > The issues that need to be resolved are the default arguments,
> > > which from my understanding are not full expressions and thus for them we do
> > > not know whether they will appear in immediate function context or not,
> > > so would we need some global flag (in_default_argument?) and just don't
> > > handle it in build_cxx_call if it is set, and then have something like
> > > cxx_eval_consteval in the recent patch invoked on the default arguments
> > > before adding it to function calls?
> >
> > It seems to me that an immediate invocation in a default argument is
> > not in immediate function context, so we can handle it normally.  The
> > only reason we need to handle immediate function context specially is
> > to allow uses of parameters of the immediate function in calls to
> > other immediate functions, and we can't refer to parameters in a
> > default argument anyway.
>
> Well, [expr.const]/(10.4) contains an example that requires it to work:
> consteval int f() { return 42; }
> consteval auto g() { return f; }
> consteval int h(int (*p)() = g()) { return p(); }
> constexpr int r = h(); // OK
> constexpr auto e = g(); // ill-formed: a pointer to an immediate function is
>                         // not a permitted result of a constant expression
> When parsing the g() expression as default argument, we don't know it will
> be a default argument of a consteval function.

g() is in immediate function context because h is consteval; clearly
we can't rely on current_function_decl for that.  The standard says
immediate function context is when "its innermost non-block scope is a
function parameter scope of an immediate function", which is the case
here.

> > > Wouldn't it affect also what constructors are invoked?  Say if some class
> > > has consteval constructor with int argument and non-consteval copy
> > > constructor:
> > > struct S { consteval S (int x) : s (x) {} S (const S &); int s; };
> > > should
> > > void foo () { S s = 5; }
> > > then invoke first the consteval ctor constructing some temporary and then
> > > the copy constructor?
> >
> > Yes, I think that follows.
>
> But in that case whether the temporary is created or not is no longer an
> implementation detail, so is it clear and can be clarified in the standard
> that a temporary must be created, so that other implementations will handle
> it the same?

Yes, I've already sent mail to the list.

Jason
Jakub Jelinek Oct. 24, 2019, 11:47 a.m. UTC | #12
On Tue, Oct 22, 2019 at 10:57:42AM -0400, Jason Merrill wrote:
> > So, do you prefer to do it the other way during build_cxx_call?
> 
> It seems more straightforward.

I've tried this approach, but am running into issues:
1) the normal constructors aren't an issue, all I was missing is passing
   the object argument down to cxx_constant_value.  The only problem
   (I'm aware of) is then the case where build_over_call is called on
   a constructor on is_dummy_object, because that obviously isn't
   usable in constant expression as something to store into.  This is
   used e.g. in the value initialization in consteval8.C test, but probably
   for vec init too and other cases.  I've tried to create a temporary in
   that case, but consteval8.C still ICEs
/usr/src/gcc/gcc/testsuite/g++.dg/cpp2a/consteval8.C: In function 'int foo()':
/usr/src/gcc/gcc/testsuite/g++.dg/cpp2a/consteval8.C:13:13: internal compiler error: tree check: expected aggr_init_expr, have target_expr in build
_value_init, at cp/init.c:372
0x190aa02 tree_check_failed(tree_node const*, char const*, int, char const*, ...)
        ../../gcc/tree.c:9925
0x8c37d8 tree_check(tree_node*, char const*, int, char const*, tree_code)
        ../../gcc/tree.h:3267
0xa254b5 build_value_init(tree_node*, int)
        ../../gcc/cp/init.c:372
2) all other testcases in the testsuite pass, but I'm worried about
   default arguments in consteval lambdas.
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);
  constexpr auto d = qux (bar);
  constexpr auto e = qux ();
  static_assert (c == 1);
  static_assert (d == 42);
  static_assert (e == 42);
}
  I believe qux (baz) and qux (bar) are invalid and the patch rejects
  it (I think innermost non-block scope for the baz in qux (baz) is
  not a function parameter scope of an immediate function and so taking
  the address there is invalid.  But isn't the qux () call ok?
  I mean it is similar to the non-lambda calls in the example in the
  standard.  Unfortunately, when parsing the default arguments of a
  lambda, we haven't seen the consteval keyword yet.  I think we could
  tentatively set the consteval argument scope when parsing any lambda
  and if it is not consteval, call a cxx_eval_consteval like function
  to evaluate it at that point.  Thoughts on that?

3) compared to the May version of the patch, I also found that
   build_over_call has a completely separate path if
   processing_template_decl and does something much simpler in that
   case, but I believe we still need to evaluate consteval calls
   even if processing_template_decl if they aren't dependent.

2019-10-24  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.
	(build_local_temp): Declare.
	(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.
	* tree.c (build_local_temp): Remove forward declaration, no longer
	static.
	* 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_lambda_declarator_opt): Handle ds_consteval.
	(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.
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/ext/consteval1.C: New test.

--- gcc/c-family/c-common.h.jj	2019-10-23 20:37:59.975872365 +0200
+++ gcc/c-family/c-common.h	2019-10-24 12:14:12.023935147 +0200
@@ -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-23 20:37:59.976872350 +0200
+++ gcc/c-family/c-common.c	2019-10-24 12:14:12.023935147 +0200
@@ -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-24 12:07:14.830380957 +0200
+++ gcc/cp/cp-tree.h	2019-10-24 12:50:39.078061855 +0200
@@ -2690,7 +2690,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.  */
 
@@ -3204,6 +3205,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.
@@ -5867,6 +5877,7 @@ enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7286,6 +7297,7 @@ extern tree build_min_nt_call_vec (tree,
 extern tree build_min_non_dep_call_vec		(tree, tree, vec<tree, va_gc> *);
 extern vec<tree, va_gc>* vec_copy_and_insert    (vec<tree, va_gc>*, tree, unsigned);
 extern tree build_cplus_new			(tree, tree, tsubst_flags_t);
+extern tree build_local_temp			(tree);
 extern tree build_aggr_init_expr		(tree, tree);
 extern tree get_target_expr			(tree);
 extern tree get_target_expr_sfinae		(tree, tsubst_flags_t);
@@ -7803,7 +7815,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-23 20:38:00.021871669 +0200
+++ gcc/cp/name-lookup.h	2019-10-24 12:14:12.014935286 +0200
@@ -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/tree.c.jj	2019-10-23 14:33:17.571963765 +0200
+++ gcc/cp/tree.c	2019-10-24 12:50:00.331662115 +0200
@@ -43,7 +43,6 @@ static hashval_t list_hash_pieces (tree,
 static tree build_target_expr (tree, tree, tsubst_flags_t);
 static tree count_trees_r (tree *, int *, void *);
 static tree verify_stmt_tree_r (tree *, int *, void *);
-static tree build_local_temp (tree);
 
 static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
 static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
@@ -525,7 +524,7 @@ build_target_expr (tree decl, tree value
 /* Return an undeclared local temporary of type TYPE for use in building a
    TARGET_EXPR.  */
 
-static tree
+tree
 build_local_temp (tree type)
 {
   tree slot = build_decl (input_location,
--- gcc/cp/parser.c.jj	2019-10-24 12:07:14.771381868 +0200
+++ gcc/cp/parser.c	2019-10-24 12:14:11.596941737 +0200
@@ -995,11 +995,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:
@@ -1827,12 +1829,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
@@ -10994,6 +10999,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);
 
@@ -14054,6 +14062,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);
@@ -14171,7 +14184,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 +17324,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 +20313,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 +20960,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 +29985,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-23 20:38:00.023871638 +0200
+++ gcc/cp/call.c	2019-10-24 13:07:22.950530039 +0200
@@ -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,31 @@ 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))
+	    {
+	      obj_arg = build_local_temp (TREE_TYPE (obj_arg));
+	      exprimm = build_call_array_loc (input_location, return_type,
+					      addr, nargs, argarray);
+	      tree c = extract_call_expr (exprimm);
+	      if (TREE_CODE (c) == CALL_EXPR)
+		CALL_EXPR_ARG (c, 0) = build_this (obj_arg);
+	    }
+	  fold_non_dependent_expr (exprimm, complain,
+				   /*manifestly_const_eval=*/true,
+				   obj_arg);
+	}
       return convert_from_reference (expr);
     }
 
@@ -8744,6 +8772,31 @@ 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))
+	    {
+	      tree c = extract_call_expr (call);
+	      if (TREE_CODE (c) == CALL_EXPR)
+		{
+		  obj_arg = build_local_temp (TREE_TYPE (obj_arg));
+		  CALL_EXPR_ARG (c, 0) = build_this (obj_arg);
+		}
+	    }
+	  call = cxx_constant_value (call, obj_arg);
+	}
+    }
   return call;
 }
 
--- gcc/cp/error.c.jj	2019-10-23 20:37:59.981872274 +0200
+++ gcc/cp/error.c	2019-10-24 12:14:11.597941722 +0200
@@ -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-23 20:37:59.983872244 +0200
+++ gcc/cp/semantics.c	2019-10-24 12:14:12.016935255 +0200
@@ -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-24 12:07:04.261544248 +0200
+++ gcc/cp/typeck.c	2019-10-24 12:14:11.598941706 +0200
@@ -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-24 12:07:14.690383120 +0200
+++ gcc/cp/decl.c	2019-10-24 12:14:11.590941830 +0200
@@ -1224,7 +1224,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))
@@ -1232,6 +1238,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]
@@ -1241,9 +1249,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;
@@ -5013,12 +5026,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)
@@ -5376,11 +5392,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)
@@ -9133,6 +9152,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);
@@ -9180,7 +9208,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;
@@ -9219,6 +9250,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.
@@ -10577,6 +10613,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;
@@ -10849,17 +10886,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;
     }
 
@@ -11265,21 +11316,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;
 	}
     }
 
@@ -11302,9 +11363,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 "
@@ -11364,6 +11428,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)
 	{
@@ -12758,7 +12823,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)
@@ -12768,6 +12833,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)
 	      {
@@ -12789,6 +12860,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)
 	      {
@@ -12819,7 +12898,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,
@@ -12921,8 +13001,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),
@@ -12930,6 +13010,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]);
@@ -12954,23 +13038,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)
@@ -13076,6 +13171,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
@@ -13086,7 +13189,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,
@@ -13179,6 +13283,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]);
@@ -16448,7 +16558,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
@@ -16565,7 +16675,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-24 12:07:04.322543306 +0200
+++ gcc/cp/constexpr.c	2019-10-24 12:35:17.624337097 +0200
@@ -5651,6 +5651,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
@@ -5679,13 +5689,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))
     {
@@ -5786,6 +5821,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.  */
@@ -6026,7 +6080,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);
 
@@ -6047,7 +6102,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)
@@ -6083,16 +6138,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);
 }
 
 
@@ -6109,7 +6165,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 12:07:14.732382470 +0200
+++ gcc/cp/method.c	2019-10-24 12:14:11.598941706 +0200
@@ -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-23 20:37:59.983872244 +0200
+++ gcc/cp/lambda.c	2019-10-24 12:14:11.598941706 +0200
@@ -1188,6 +1188,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)
@@ -1220,6 +1223,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/testsuite/g++.dg/cpp2a/consteval1.C.jj	2019-10-24 12:14:12.020935193 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval1.C	2019-10-24 12:14:12.020935193 +0200
@@ -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-24 12:14:12.019935209 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval2.C	2019-10-24 12:14:12.019935209 +0200
@@ -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-24 12:14:12.019935209 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C	2019-10-24 12:14:12.019935209 +0200
@@ -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-24 12:14:12.020935193 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval4.C	2019-10-24 12:14:12.020935193 +0200
@@ -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-24 12:14:12.021935178 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval5.C	2019-10-24 12:14:12.021935178 +0200
@@ -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-24 12:14:12.021935178 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval6.C	2019-10-24 12:14:12.021935178 +0200
@@ -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-24 12:14:12.020935193 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval7.C	2019-10-24 12:14:12.020935193 +0200
@@ -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-24 12:14:12.020935193 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval8.C	2019-10-24 12:14:12.020935193 +0200
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } int a, b; };
+S c;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  return S ().a;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj	2019-10-24 12:14:12.019935209 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval9.C	2019-10-24 12:14:12.019935209 +0200
@@ -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-24 12:14:12.021935178 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval10.C	2019-10-24 12:14:12.021935178 +0200
@@ -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-24 12:14:12.019935209 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval11.C	2019-10-24 12:14:12.019935209 +0200
@@ -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-24 12:14:12.018935224 +0200
+++ gcc/testsuite/g++.dg/ext/consteval1.C	2019-10-24 12:14:12.018935224 +0200
@@ -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" }


	Jakub
Jason Merrill Oct. 30, 2019, 9:06 p.m. UTC | #13
On 10/24/19 7:47 AM, Jakub Jelinek wrote:
> On Tue, Oct 22, 2019 at 10:57:42AM -0400, Jason Merrill wrote:
>>> So, do you prefer to do it the other way during build_cxx_call?
>>
>> It seems more straightforward.
> 
> I've tried this approach, but am running into issues:
> 1) the normal constructors aren't an issue, all I was missing is passing
>     the object argument down to cxx_constant_value.  The only problem
>     (I'm aware of) is then the case where build_over_call is called on
>     a constructor on is_dummy_object, because that obviously isn't
>     usable in constant expression as something to store into.  This is
>     used e.g. in the value initialization in consteval8.C test, but probably
>     for vec init too and other cases.  I've tried to create a temporary in
>     that case, but consteval8.C still ICEs
> /usr/src/gcc/gcc/testsuite/g++.dg/cpp2a/consteval8.C: In function 'int foo()':
> /usr/src/gcc/gcc/testsuite/g++.dg/cpp2a/consteval8.C:13:13: internal compiler error: tree check: expected aggr_init_expr, have target_expr in build
> _value_init, at cp/init.c:372
> 0x190aa02 tree_check_failed(tree_node const*, char const*, int, char const*, ...)
>          ../../gcc/tree.c:9925
> 0x8c37d8 tree_check(tree_node*, char const*, int, char const*, tree_code)
>          ../../gcc/tree.h:3267
> 0xa254b5 build_value_init(tree_node*, int)
>          ../../gcc/cp/init.c:372

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.

> 2) all other testcases in the testsuite pass, but I'm worried about
>     default arguments in consteval lambdas.
> 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);
>    constexpr auto d = qux (bar);
>    constexpr auto e = qux ();
>    static_assert (c == 1);
>    static_assert (d == 42);
>    static_assert (e == 42);
> }
>    I believe qux (baz) and qux (bar) are invalid and the patch rejects
>    it (I think innermost non-block scope for the baz in qux (baz) is
>    not a function parameter scope of an immediate function and so taking
>    the address there is invalid.  But isn't the qux () call ok?
>    I mean it is similar to the non-lambda calls in the example in the
>    standard.  Unfortunately, when parsing the default arguments of a
>    lambda, we haven't seen the consteval keyword yet.  I think we could
>    tentatively set the consteval argument scope when parsing any lambda
>    and if it is not consteval, call a cxx_eval_consteval like function
>    to evaluate it at that point.  Thoughts on that?

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

On the other hand, your suggestion also sounds reasonable, and if we do 
that for lambdas, we could do it for all functions instead of messing 
with the binding level.

Up to you.

> 3) compared to the May version of the patch, I also found that
>     build_over_call has a completely separate path if
>     processing_template_decl and does something much simpler in that
>     case, but I believe we still need to evaluate consteval calls
>     even if processing_template_decl if they aren't dependent.

I think such calls fall under the rule that if no valid instantiation is 
possible, the function is ill-formed, no diagnostic required.

So it's desirable, but not necessary.

> 2019-10-24  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.
> 	(build_local_temp): Declare.
> 	(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.
> 	* tree.c (build_local_temp): Remove forward declaration, no longer
> 	static.
> 	* 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_lambda_declarator_opt): Handle ds_consteval.
> 	(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.
> 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/ext/consteval1.C: New test.
> 
> --- gcc/c-family/c-common.h.jj	2019-10-23 20:37:59.975872365 +0200
> +++ gcc/c-family/c-common.h	2019-10-24 12:14:12.023935147 +0200
> @@ -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-23 20:37:59.976872350 +0200
> +++ gcc/c-family/c-common.c	2019-10-24 12:14:12.023935147 +0200
> @@ -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-24 12:07:14.830380957 +0200
> +++ gcc/cp/cp-tree.h	2019-10-24 12:50:39.078061855 +0200
> @@ -2690,7 +2690,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.  */
>   
> @@ -3204,6 +3205,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.
> @@ -5867,6 +5877,7 @@ enum cp_decl_spec {
>     ds_constexpr,
>     ds_complex,
>     ds_constinit,
> +  ds_consteval,
>     ds_thread,
>     ds_type_spec,
>     ds_redefined_builtin_type_spec,
> @@ -7286,6 +7297,7 @@ extern tree build_min_nt_call_vec (tree,
>   extern tree build_min_non_dep_call_vec		(tree, tree, vec<tree, va_gc> *);
>   extern vec<tree, va_gc>* vec_copy_and_insert    (vec<tree, va_gc>*, tree, unsigned);
>   extern tree build_cplus_new			(tree, tree, tsubst_flags_t);
> +extern tree build_local_temp			(tree);
>   extern tree build_aggr_init_expr		(tree, tree);
>   extern tree get_target_expr			(tree);
>   extern tree get_target_expr_sfinae		(tree, tsubst_flags_t);
> @@ -7803,7 +7815,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-23 20:38:00.021871669 +0200
> +++ gcc/cp/name-lookup.h	2019-10-24 12:14:12.014935286 +0200
> @@ -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/tree.c.jj	2019-10-23 14:33:17.571963765 +0200
> +++ gcc/cp/tree.c	2019-10-24 12:50:00.331662115 +0200
> @@ -43,7 +43,6 @@ static hashval_t list_hash_pieces (tree,
>   static tree build_target_expr (tree, tree, tsubst_flags_t);
>   static tree count_trees_r (tree *, int *, void *);
>   static tree verify_stmt_tree_r (tree *, int *, void *);
> -static tree build_local_temp (tree);
>   
>   static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
>   static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
> @@ -525,7 +524,7 @@ build_target_expr (tree decl, tree value
>   /* Return an undeclared local temporary of type TYPE for use in building a
>      TARGET_EXPR.  */
>   
> -static tree
> +tree
>   build_local_temp (tree type)
>   {
>     tree slot = build_decl (input_location,
> --- gcc/cp/parser.c.jj	2019-10-24 12:07:14.771381868 +0200
> +++ gcc/cp/parser.c	2019-10-24 12:14:11.596941737 +0200
> @@ -995,11 +995,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:
> @@ -1827,12 +1829,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
> @@ -10994,6 +10999,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);
>   
> @@ -14054,6 +14062,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);
> @@ -14171,7 +14184,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 +17324,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 +20313,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 +20960,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 +29985,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-23 20:38:00.023871638 +0200
> +++ gcc/cp/call.c	2019-10-24 13:07:22.950530039 +0200
> @@ -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,31 @@ 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))

Please factor out these tests.

> +	{
> +	  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))
> +	    {
> +	      obj_arg = build_local_temp (TREE_TYPE (obj_arg));
> +	      exprimm = build_call_array_loc (input_location, return_type,
> +					      addr, nargs, argarray);
> +	      tree c = extract_call_expr (exprimm);
> +	      if (TREE_CODE (c) == CALL_EXPR)
> +		CALL_EXPR_ARG (c, 0) = build_this (obj_arg);
> +	    }
> +	  fold_non_dependent_expr (exprimm, complain,
> +				   /*manifestly_const_eval=*/true,
> +				   obj_arg);
> +	}
>         return convert_from_reference (expr);
>       }
>   
> @@ -8744,6 +8772,31 @@ 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))
> +	    {
> +	      tree c = extract_call_expr (call);
> +	      if (TREE_CODE (c) == CALL_EXPR)
> +		{
> +		  obj_arg = build_local_temp (TREE_TYPE (obj_arg));
> +		  CALL_EXPR_ARG (c, 0) = build_this (obj_arg);
> +		}
> +	    }
> +	  call = cxx_constant_value (call, obj_arg);
> +	}
> +    }
>     return call;
>   }
>   
> --- gcc/cp/error.c.jj	2019-10-23 20:37:59.981872274 +0200
> +++ gcc/cp/error.c	2019-10-24 12:14:11.597941722 +0200
> @@ -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-23 20:37:59.983872244 +0200
> +++ gcc/cp/semantics.c	2019-10-24 12:14:12.016935255 +0200
> @@ -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-24 12:07:04.261544248 +0200
> +++ gcc/cp/typeck.c	2019-10-24 12:14:11.598941706 +0200
> @@ -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-24 12:07:14.690383120 +0200
> +++ gcc/cp/decl.c	2019-10-24 12:14:11.590941830 +0200
> @@ -1224,7 +1224,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))
> @@ -1232,6 +1238,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]
> @@ -1241,9 +1249,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;
> @@ -5013,12 +5026,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)
> @@ -5376,11 +5392,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)
> @@ -9133,6 +9152,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);
> @@ -9180,7 +9208,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;
> @@ -9219,6 +9250,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.
> @@ -10577,6 +10613,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;
> @@ -10849,17 +10886,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;
>       }
>   
> @@ -11265,21 +11316,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;
>   	}
>       }
>   
> @@ -11302,9 +11363,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 "
> @@ -11364,6 +11428,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)
>   	{
> @@ -12758,7 +12823,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)
> @@ -12768,6 +12833,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)
>   	      {
> @@ -12789,6 +12860,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)
>   	      {
> @@ -12819,7 +12898,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,
> @@ -12921,8 +13001,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),
> @@ -12930,6 +13010,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]);
> @@ -12954,23 +13038,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)
> @@ -13076,6 +13171,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
> @@ -13086,7 +13189,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,
> @@ -13179,6 +13283,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]);
> @@ -16448,7 +16558,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
> @@ -16565,7 +16675,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-24 12:07:04.322543306 +0200
> +++ gcc/cp/constexpr.c	2019-10-24 12:35:17.624337097 +0200
> @@ -5651,6 +5651,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
> @@ -5679,13 +5689,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))
>       {
> @@ -5786,6 +5821,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.  */
> @@ -6026,7 +6080,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);
>   
> @@ -6047,7 +6102,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)
> @@ -6083,16 +6138,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);
>   }
>   
>   
> @@ -6109,7 +6165,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 12:07:14.732382470 +0200
> +++ gcc/cp/method.c	2019-10-24 12:14:11.598941706 +0200
> @@ -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-23 20:37:59.983872244 +0200
> +++ gcc/cp/lambda.c	2019-10-24 12:14:11.598941706 +0200
> @@ -1188,6 +1188,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)
> @@ -1220,6 +1223,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/testsuite/g++.dg/cpp2a/consteval1.C.jj	2019-10-24 12:14:12.020935193 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval1.C	2019-10-24 12:14:12.020935193 +0200
> @@ -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-24 12:14:12.019935209 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval2.C	2019-10-24 12:14:12.019935209 +0200
> @@ -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-24 12:14:12.019935209 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval3.C	2019-10-24 12:14:12.019935209 +0200
> @@ -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-24 12:14:12.020935193 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval4.C	2019-10-24 12:14:12.020935193 +0200
> @@ -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-24 12:14:12.021935178 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval5.C	2019-10-24 12:14:12.021935178 +0200
> @@ -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-24 12:14:12.021935178 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval6.C	2019-10-24 12:14:12.021935178 +0200
> @@ -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-24 12:14:12.020935193 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval7.C	2019-10-24 12:14:12.020935193 +0200
> @@ -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-24 12:14:12.020935193 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval8.C	2019-10-24 12:14:12.020935193 +0200
> @@ -0,0 +1,14 @@
> +// { dg-do compile }
> +// { dg-options "-std=c++2a" }
> +
> +struct S { consteval S () : a (1), b (2) { a++; b++; } int a, b; };
> +S c;
> +
> +int
> +foo ()
> +{
> +  S a;
> +  a.b++;
> +  c = a;
> +  return S ().a;
> +}
> --- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj	2019-10-24 12:14:12.019935209 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval9.C	2019-10-24 12:14:12.019935209 +0200
> @@ -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-24 12:14:12.021935178 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval10.C	2019-10-24 12:14:12.021935178 +0200
> @@ -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-24 12:14:12.019935209 +0200
> +++ gcc/testsuite/g++.dg/cpp2a/consteval11.C	2019-10-24 12:14:12.019935209 +0200
> @@ -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-24 12:14:12.018935224 +0200
> +++ gcc/testsuite/g++.dg/ext/consteval1.C	2019-10-24 12:14:12.018935224 +0200
> @@ -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" }
> 
> 
> 	Jakub
>
diff mbox series

Patch

--- gcc/c-family/c-common.h.jj	2019-10-14 10:26:37.832352583 +0200
+++ gcc/c-family/c-common.h	2019-10-14 17:24:26.407978329 +0200
@@ -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-14 10:26:37.810352919 +0200
+++ gcc/c-family/c-common.c	2019-10-14 17:24:46.361675167 +0200
@@ -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-10 09:04:50.547692560 +0200
+++ gcc/cp/cp-tree.h	2019-10-15 12:10:51.607055382 +0200
@@ -2693,7 +2693,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.  */
 
@@ -3207,6 +3208,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.
@@ -5861,6 +5871,7 @@  enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7799,6 +7810,7 @@  extern tree fold_non_dependent_expr		(tr
 extern tree fold_non_dependent_init		(tree,
 						 tsubst_flags_t = tf_warning_or_error,
 						 bool = false);
+extern tree cxx_eval_consteval			(tree);
 extern tree fold_simple				(tree);
 extern bool reduced_constant_expression_p       (tree);
 extern bool is_instantiation_of_constexpr       (tree);
--- gcc/cp/parser.c.jj	2019-10-14 08:52:03.704579127 +0200
+++ gcc/cp/parser.c	2019-10-15 14:08:06.963289881 +0200
@@ -995,11 +995,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:
@@ -1827,7 +1829,8 @@  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,
@@ -8580,7 +8583,10 @@  cp_parser_has_attribute_expression (cp_p
   /* If the type-id production did not work out, then we must be
      looking at an expression.  */
   if (!oper || oper == error_mark_node)
-    oper = cp_parser_assignment_expression (parser);
+    {
+      oper = cp_parser_assignment_expression (parser);
+      oper = cxx_eval_consteval (oper);
+    }
 
   STRIP_ANY_LOCATION_WRAPPER (oper);
 
@@ -10998,6 +11004,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);
 
@@ -14059,6 +14068,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);
@@ -14176,7 +14190,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]);
 
@@ -17315,6 +17330,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);
@@ -29964,9 +29983,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-10 01:33:38.283942013 +0200
+++ gcc/cp/call.c	2019-10-15 10:49:56.837744805 +0200
@@ -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);
 
--- gcc/cp/error.c.jj	2019-10-10 01:33:38.187943450 +0200
+++ gcc/cp/error.c	2019-10-14 16:52:27.707101444 +0200
@@ -1648,7 +1648,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-14 10:11:32.396100623 +0200
+++ gcc/cp/semantics.c	2019-10-15 12:26:52.389473220 +0200
@@ -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)))))
@@ -9628,6 +9629,8 @@  finish_decltype_type (tree expr, bool id
       return error_mark_node;
     }
 
+  expr = cxx_eval_consteval (expr);
+
   /* Depending on the resolution of DR 1172, we may later need to distinguish
      instantiation-dependent but not type-dependent expressions so that, say,
      A<decltype(sizeof(T))>::U doesn't require 'typename'.  */
--- gcc/cp/typeck.c.jj	2019-10-12 10:21:30.256263248 +0200
+++ gcc/cp/typeck.c	2019-10-15 12:28:35.530907909 +0200
@@ -1860,10 +1860,11 @@  cxx_alignof_expr (tree e, tsubst_flags_t
 tree
 cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
 {
+  e = cxx_eval_consteval (e);
   if (op == SIZEOF_EXPR)
-    return cxx_sizeof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_sizeof_expr (e, complain ? tf_warning_or_error : tf_none);
   else
-    return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_alignof_expr (e, complain ? tf_warning_or_error : tf_none);
 }
 
 /*  Build a representation of an expression 'alignas(E).'  Return the
@@ -6177,6 +6178,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-15 18:34:22.724179075 +0200
+++ gcc/cp/decl.c	2019-10-15 18:50:35.719370678 +0200
@@ -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;
@@ -5034,12 +5047,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)
@@ -5397,11 +5413,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)
@@ -6559,6 +6578,9 @@  check_initializer (tree decl, tree init,
     /* There is no way to make a variable-sized class type in GNU C++.  */
     gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
 
+  if (init && TREE_STATIC (decl))
+    init = cxx_eval_consteval (init);
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
     {
       int init_len = CONSTRUCTOR_NELTS (init);
@@ -9154,6 +9176,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);
@@ -9201,7 +9232,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;
@@ -9240,6 +9274,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.
@@ -10604,6 +10643,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;
@@ -10876,17 +10916,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;
     }
 
@@ -11292,21 +11346,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;
 	}
     }
 
@@ -11329,9 +11393,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 "
@@ -11391,6 +11458,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)
 	{
@@ -12788,7 +12856,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)
@@ -12798,6 +12866,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)
 	      {
@@ -12819,6 +12893,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)
 	      {
@@ -12849,7 +12931,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,
@@ -12951,8 +13034,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),
@@ -12960,6 +13043,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]);
@@ -12984,23 +13071,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)
@@ -13106,6 +13204,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
@@ -13116,7 +13222,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,
@@ -13209,6 +13316,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]);
@@ -16469,6 +16582,9 @@  finish_function (bool inline_p)
 	  || is_valid_constexpr_fn (fndecl, /*complain*/false))
 	 && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
 
+  if (!DECL_IMMEDIATE_FUNCTION_P (fndecl))
+    DECL_SAVED_TREE (fndecl) = cxx_eval_consteval (DECL_SAVED_TREE (fndecl));
+
   /* Save constexpr function body before it gets munged by
      the NRV transformation.   */
   maybe_save_function_definition (fndecl);
@@ -16478,7 +16594,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
@@ -16595,7 +16711,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-12 10:21:30.258263218 +0200
+++ gcc/cp/constexpr.c	2019-10-15 15:33:18.390730126 +0200
@@ -1022,8 +1022,10 @@  struct constexpr_global_ctx {
   /* Heap VAR_DECLs created during the evaluation of the outermost constant
      expression.  */
   auto_vec<tree, 16> heap_vars;
+  /* True if evaluating a call to consteval function.  */
+  bool in_consteval;
   /* Constructor.  */
-  constexpr_global_ctx () : constexpr_ops_count (0) {}
+  constexpr_global_ctx () : constexpr_ops_count (0), in_consteval (false) {}
 };
 
 /* The constexpr expansion context.  CALL is the current function
@@ -1663,6 +1665,20 @@  cxx_eval_call_expression (const constexp
 	    }
 	}
     }
+  else if (DECL_IMMEDIATE_FUNCTION_P (fun)
+	   && !ctx->global->in_consteval
+	   && (current_function_decl == NULL_TREE
+	       || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    {
+      tree c = cxx_constant_value (t, NULL_TREE);
+      if (c == t || c == error_mark_node)
+	{
+	  *non_constant_p = true;
+	  return t;
+	}
+      return cxx_eval_constant_expression (ctx, c, lval, non_constant_p,
+					   overflow_p);
+    }
   if (TREE_CODE (fun) != FUNCTION_DECL)
     {
       if (!ctx->quiet && !*non_constant_p)
@@ -5641,6 +5657,17 @@  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
@@ -5675,7 +5702,26 @@  cxx_eval_outermost_constant_expr (tree t
 	/* 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
+	    global_ctx.in_consteval = true;
+	}
+    }
+  else if (cxx_dialect >= cxx2a
+	   && (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR))
+    {
+      tree fndecl = cp_get_callee_fndecl_nofold (t);
+      if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+	global_ctx.in_consteval = true;
     }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
@@ -5776,6 +5822,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 (global_ctx.in_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.  */
@@ -5865,6 +5930,63 @@  cxx_constant_dtor (tree t, tree decl)
   cxx_eval_outermost_constant_expr (t, false, true, true, true, decl);
 }
 
+static tree
+fold_non_dependent_expr_template (tree, tsubst_flags_t, bool, bool);
+
+/* Helper function for cxx_eval_consteval.  Find calls to immediate
+   functions in *TP and evaluate them.  */
+
+static tree
+cxx_eval_consteval_r (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
+    {
+      tree callee = cp_get_callee (*tp);
+      if (processing_template_decl
+	  && callee
+	  && TREE_CODE (callee) != FUNCTION_DECL
+	  && (TREE_TYPE (callee) == NULL_TREE
+	      || !INDIRECT_TYPE_P (TREE_TYPE (callee))))
+	return NULL_TREE;
+      callee = cp_get_fndecl_from_callee (callee, false);
+      if (callee && DECL_IMMEDIATE_FUNCTION_P (callee))
+	{
+	  if (processing_template_decl)
+	    fold_non_dependent_expr_template (*tp, tf_warning_or_error,
+					      /*allow_non_constant*/false,
+					      /*manifestly_const_eval=*/ true);
+	  else
+	    {
+	      int saved_errorcount = errorcount;
+	      tree t = cxx_constant_value (*tp, NULL_TREE);
+	      if (t != *tp)
+		*tp = t;
+	      else
+		{
+		  /* Error recovery, make sure we don't diagnose it multiple
+		     times.  */
+		  gcc_assert (errorcount > saved_errorcount);
+		  if (VOID_TYPE_P (TREE_TYPE (*tp)))
+		    *tp = void_node;
+		  else
+		    *tp = build_zero_cst (t);
+		}
+	    }
+	}
+    }
+  return NULL_TREE;
+}
+
+/* Evaluate calls to immediate functions in T.  */
+
+tree
+cxx_eval_consteval (tree t)
+{
+  if (cxx_dialect >= cxx2a)
+    cp_walk_tree_without_duplicates (&t, cxx_eval_consteval_r, NULL);
+  return t;
+}
+
 /* Helper routine for fold_simple function.  Either return simplified
    expression T, otherwise NULL_TREE.
    In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
@@ -6016,6 +6138,7 @@  clear_cv_and_fold_caches (bool sat /*= t
 
 static tree
 fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
+				  bool allow_non_constant,
 				  bool manifestly_const_eval)
 {
   gcc_assert (processing_template_decl);
@@ -6035,7 +6158,7 @@  fold_non_dependent_expr_template (tree t
 	  return t;
 	}
 
-      tree r = cxx_eval_outermost_constant_expr (t, true, true,
+      tree r = cxx_eval_outermost_constant_expr (t, allow_non_constant, true,
 						 manifestly_const_eval,
 						 false, NULL_TREE);
       /* cp_tree_equal looks through NOPs, so allow them.  */
@@ -6080,6 +6203,7 @@  fold_non_dependent_expr (tree t,
 
   if (processing_template_decl)
     return fold_non_dependent_expr_template (t, complain,
+					     /*allow_non_constant*/true,
 					     manifestly_const_eval);
 
   return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
@@ -6099,6 +6223,7 @@  fold_non_dependent_init (tree t,
   if (processing_template_decl)
     {
       t = fold_non_dependent_expr_template (t, complain,
+					    /*allow_non_constant*/true,
 					    manifestly_const_eval);
       /* maybe_constant_init does this stripping, so do it here too.  */
       if (TREE_CODE (t) == TARGET_EXPR)
--- gcc/cp/method.c.jj	2019-10-12 10:21:30.257263232 +0200
+++ gcc/cp/method.c	2019-10-14 18:23:24.258313542 +0200
@@ -2256,8 +2256,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/except.c.jj	2019-06-25 08:57:57.706484715 +0200
+++ gcc/cp/except.c	2019-10-15 13:56:59.833413107 +0200
@@ -1191,6 +1191,8 @@  finish_noexcept_expr (tree expr, tsubst_
   if (expr == error_mark_node)
     return error_mark_node;
 
+  expr = cxx_eval_consteval (expr);
+
   if (processing_template_decl)
     return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
 
--- gcc/cp/lambda.c.jj	2019-10-10 01:33:38.284941998 +0200
+++ gcc/cp/lambda.c	2019-10-15 13:41:52.372183503 +0200
@@ -1189,6 +1189,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)
@@ -1221,6 +1224,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/testsuite/g++.dg/cpp2a/consteval1.C.jj	2019-10-14 16:52:27.711101384 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval1.C	2019-10-14 16:52:27.711101384 +0200
@@ -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-14 16:52:27.712101369 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval2.C	2019-10-14 16:52:27.712101369 +0200
@@ -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-14 16:52:27.712101369 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C	2019-10-15 16:28:25.253572602 +0200
@@ -0,0 +1,62 @@ 
+// { 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 "" }
+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-14 16:52:27.712101369 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval4.C	2019-10-14 16:52:27.712101369 +0200
@@ -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-14 16:52:27.712101369 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval5.C	2019-10-14 16:52:27.712101369 +0200
@@ -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-14 16:52:27.712101369 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval6.C	2019-10-14 16:52:27.712101369 +0200
@@ -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-14 16:52:27.726101156 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval7.C	2019-10-15 11:32:51.815658571 +0200
@@ -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-15 10:29:50.229065304 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval8.C	2019-10-15 10:30:33.032415274 +0200
@@ -0,0 +1,14 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } int a, b; };
+S c;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  return S ().a;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj	2019-10-15 13:09:39.781510537 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval9.C	2019-10-15 13:11:52.785492131 +0200
@@ -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-15 13:12:24.741007195 +0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval10.C	2019-10-15 13:13:29.032031549 +0200
@@ -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/ext/consteval1.C.jj	2019-10-15 14:06:18.667933180 +0200
+++ gcc/testsuite/g++.dg/ext/consteval1.C	2019-10-15 15:33:18.391730111 +0200
@@ -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" }