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  <ja...@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

Reply via email to