This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]