Hi!

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

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

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

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

2019-10-15  Jakub Jelinek  <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.
        (cxx_eval_consteval): Declare.
        * parser.c (cp_keyword_starts_decl_specifier_p): Adjust comments
        for C++11 and C++20 specifiers.  Handle RID_CONSTEVAL.
        (CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Adjust comment.
        (cp_parser_has_attribute_expression): Call cxx_eval_consteval.
        (cp_parser_lambda_declarator_opt): Handle ds_consteval.
        (cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
        (cp_parser_explicit_instantiation): Diagnose explicit instantiation
        with consteval specifier.
        (set_and_check_decl_spec_loc): Add consteval entry, formatting fix.
        * call.c (build_addr_func): For direct calls to immediate functions
        use build_address rather than decay_conversion.
        * error.c (dump_function_decl): Handle DECL_IMMEDIATE_FUNCTION_P.
        * semantics.c (expand_or_defer_fn_1): Use tentative linkage and don't
        call mark_needed for immediate functions.
        (finish_decltype_type): Call cxx_eval_consteval.
        * typeck.c (cxx_sizeof_or_alignof_expr): Likewise.  Formatting fix.
        (cp_build_addr_expr_1): Reject taking address of immediate function
        outside of immediate function.
        * decl.c (validate_constexpr_redeclaration): Diagnose consteval
        vs. non-consteval or vice versa redeclaration.  Use
        SET_DECL_IMMEDIATE_FUNCTION_P if new_decl is immediate function.
        (check_tag_decl): Use %qs with keyword string to simplify translation.
        Handle ds_consteval.
        (start_decl): Adjust diagnostics for static or thread_local variables
        in immediate functions.
        (check_initializer): Call cxx_eval_consteval.
        (grokfndecl): Call sorry_at on virtual consteval.  Use %qs with keyword
        to string to simplify translation.  Diagnose consteval main.  Use
        SET_DECL_IMMEDIATE_FUNCTION_P for consteval.
        (grokdeclarator): Handle consteval.  Use %qs with keyword strings to
        simplify translation.  Use separate ifs instead of chained else if
        for invalid specifiers.  For constinit clear constinit_p rather than
        constexpr_p.
        (finish_function): Call cxx_eval_consteval for non-immediate functions.
        * constexpr.c (struct constexpr_global_ctx): Add in_consteval field,
        initialize it in the constructor.
        (cxx_eval_call_expression): When encountering immediate function call
        outside of in_consteval and outside of immediate function, call
        cxx_constant_value.
        (find_immediate_fndecl): New function.
        (cxx_eval_outermost_constant_expr): Allow consteval calls returning
        void.  Set global_ctx.in_consteval.  Diagnose returning address of
        immediate function from in_consteval evaluation.
        (fold_non_dependent_expr_template): Add forward declaration.  Add
        allow_non_constant argument and pass it through to
        cxx_eval_outermost_constant_expr.
        (cxx_eval_consteval_r, cxx_eval_consteval): New functions.
        (fold_non_dependent_expr, fold_non_dependent_init): Adjust
        fold_non_dependent_expr_template callers.
        * method.c (defaulted_late_check): Adjust diagnostics for consteval.
        * except.c (finish_noexcept_expr): Call cxx_eval_consteval.
        * lambda.c (maybe_add_lambda_conv_op): Copy over
        DECL_DECLARED_CONSTEXPR_P and DECL_IMMEDIATE_FUNCTION_P bits from
        callop to both artificial functions.
testsuite/
        * g++.dg/cpp2a/consteval1.C: New test.
        * g++.dg/cpp2a/consteval2.C: New test.
        * g++.dg/cpp2a/consteval3.C: New test.
        * g++.dg/cpp2a/consteval4.C: New test.
        * g++.dg/cpp2a/consteval5.C: New test.
        * g++.dg/cpp2a/consteval6.C: New test.
        * g++.dg/cpp2a/consteval7.C: New test.
        * g++.dg/cpp2a/consteval8.C: New test.
        * g++.dg/cpp2a/consteval9.C: New test.
        * g++.dg/cpp2a/consteval10.C: New test.
        * g++.dg/ext/consteval1.C: New test.

--- gcc/c-family/c-common.h.jj  2019-10-14 10:26:37.832352583 +0200
+++ gcc/c-family/c-common.h     2019-10-14 17:24:26.407978329 +0200
@@ -181,7 +181,7 @@ enum rid
   RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
 
   /* C++20 */
-  RID_CONSTINIT,
+  RID_CONSTINIT, RID_CONSTEVAL,
 
   /* char8_t */
   RID_CHAR8,
--- gcc/c-family/c-common.c.jj  2019-10-14 10:26:37.810352919 +0200
+++ gcc/c-family/c-common.c     2019-10-14 17:24:46.361675167 +0200
@@ -459,6 +459,7 @@ const struct c_common_resword c_common_r
   { "char32_t",                RID_CHAR32,     D_CXXONLY | D_CXX11 | D_CXXWARN 
},
   { "class",           RID_CLASS,      D_CXX_OBJC | D_CXXWARN },
   { "const",           RID_CONST,      0 },
+  { "consteval",       RID_CONSTEVAL,  D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "constexpr",       RID_CONSTEXPR,  D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "constinit",       RID_CONSTINIT,  D_CXXONLY | D_CXX20 | D_CXXWARN },
   { "const_cast",      RID_CONSTCAST,  D_CXXONLY | D_CXXWARN },
--- gcc/cp/cp-tree.h.jj 2019-10-10 09:04:50.547692560 +0200
+++ gcc/cp/cp-tree.h    2019-10-15 12:10:51.607055382 +0200
@@ -2693,7 +2693,8 @@ struct GTY(()) lang_decl_fn {
   unsigned hidden_friend_p : 1;
   unsigned omp_declare_reduction_p : 1;
   unsigned has_dependent_explicit_spec_p : 1;
-  unsigned spare : 12;
+  unsigned immediate_fn_p : 1;
+  unsigned spare : 11;
 
   /* 32-bits padding on 64-bit host.  */
 
@@ -3207,6 +3208,15 @@ struct GTY(()) lang_decl {
 #define DECL_DECLARED_CONSTEXPR_P(DECL) \
   DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
 
+/* True if FNDECL is an immediate function.  */
+#define DECL_IMMEDIATE_FUNCTION_P(NODE) \
+  (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (STRIP_TEMPLATE (NODE)))    \
+   ? LANG_DECL_FN_CHECK (NODE)->immediate_fn_p                         \
+   : false)
+#define SET_DECL_IMMEDIATE_FUNCTION_P(NODE) \
+  (retrofit_lang_decl (FUNCTION_DECL_CHECK (NODE)),                    \
+   LANG_DECL_FN_CHECK (NODE)->immediate_fn_p = true)
+
 // True if NODE was declared as 'concept'.  The flag implies that the
 // declaration is constexpr, that the declaration cannot be specialized or
 // refined, and that the result type must be convertible to bool.
@@ -5861,6 +5871,7 @@ enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7799,6 +7810,7 @@ extern tree fold_non_dependent_expr               (tr
 extern tree fold_non_dependent_init            (tree,
                                                 tsubst_flags_t = 
tf_warning_or_error,
                                                 bool = false);
+extern tree cxx_eval_consteval                 (tree);
 extern tree fold_simple                                (tree);
 extern bool reduced_constant_expression_p       (tree);
 extern bool is_instantiation_of_constexpr       (tree);
--- gcc/cp/parser.c.jj  2019-10-14 08:52:03.704579127 +0200
+++ gcc/cp/parser.c     2019-10-15 14:08:06.963289881 +0200
@@ -995,11 +995,13 @@ cp_keyword_starts_decl_specifier_p (enum
       /* GNU extensions.  */
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
-      /* C++0x extensions.  */
+      /* C++11 extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
     case RID_CONSTEXPR:
+      /* C++20 extensions.  */
     case RID_CONSTINIT:
+    case RID_CONSTEVAL:
       return true;
 
     default:
@@ -1827,7 +1829,8 @@ enum
   /* When parsing a decl-specifier-seq, only allow type-specifier or
      constexpr.  */
   CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
-  /* When parsing a decl-specifier-seq, only allow mutable or constexpr.  */
+  /* When parsing a decl-specifier-seq, only allow mutable, constexpr or
+     for C++2A consteval.  */
   CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
   /* When parsing a decl-specifier-seq, allow missing typename.  */
   CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
@@ -8580,7 +8583,10 @@ cp_parser_has_attribute_expression (cp_p
   /* If the type-id production did not work out, then we must be
      looking at an expression.  */
   if (!oper || oper == error_mark_node)
-    oper = cp_parser_assignment_expression (parser);
+    {
+      oper = cp_parser_assignment_expression (parser);
+      oper = cxx_eval_consteval (oper);
+    }
 
   STRIP_ANY_LOCATION_WRAPPER (oper);
 
@@ -10998,6 +11004,9 @@ cp_parser_lambda_declarator_opt (cp_pars
                    "lambda only available with %<-std=c++17%> or "
                    "%<-std=gnu++17%>");
       }
+    if (lambda_specs.locations[ds_consteval])
+      return_type_specs.locations[ds_consteval]
+       = lambda_specs.locations[ds_consteval];
 
     p = obstack_alloc (&declarator_obstack, 0);
 
@@ -14059,6 +14068,11 @@ cp_parser_decl_specifier_seq (cp_parser*
          cp_lexer_consume_token (parser->lexer);
          break;
 
+       case RID_CONSTEVAL:
+         ds = ds_consteval;
+         cp_lexer_consume_token (parser->lexer);
+         break;
+
         case RID_CONCEPT:
           ds = ds_concept;
           cp_lexer_consume_token (parser->lexer);
@@ -14176,7 +14190,8 @@ cp_parser_decl_specifier_seq (cp_parser*
       if (found_decl_spec
          && (flags & CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR)
          && token->keyword != RID_MUTABLE
-         && token->keyword != RID_CONSTEXPR)
+         && token->keyword != RID_CONSTEXPR
+         && token->keyword != RID_CONSTEVAL)
        error_at (token->location, "%qD invalid in lambda",
                  ridpointers[token->keyword]);
 
@@ -17315,6 +17330,10 @@ cp_parser_explicit_instantiation (cp_par
            permerror (decl_specifiers.locations[ds_constexpr],
                       "explicit instantiation shall not use"
                       " %<constexpr%> specifier");
+         if (decl_spec_seq_has_spec_p (&decl_specifiers, ds_consteval))
+           permerror (decl_specifiers.locations[ds_consteval],
+                      "explicit instantiation shall not use"
+                      " %<consteval%> specifier");
 
          decl = grokdeclarator (declarator, &decl_specifiers,
                                 NORMAL, 0, &decl_specifiers.attributes);
@@ -29964,9 +29983,10 @@ set_and_check_decl_spec_loc (cp_decl_spe
            "friend",
            "typedef",
            "using",
-            "constexpr",
+           "constexpr",
            "__complex",
-           "constinit"
+           "constinit",
+           "consteval"
          };
          gcc_rich_location richloc (location);
          richloc.add_fixit_remove ();
--- gcc/cp/call.c.jj    2019-10-10 01:33:38.283942013 +0200
+++ gcc/cp/call.c       2019-10-15 10:49:56.837744805 +0200
@@ -289,6 +289,9 @@ build_addr_func (tree function, tsubst_f
        }
       function = build_address (function);
     }
+  else if (TREE_CODE (function) == FUNCTION_DECL
+          && DECL_IMMEDIATE_FUNCTION_P (function))
+    function = build_address (function);
   else
     function = decay_conversion (function, complain, /*reject_builtin=*/false);
 
--- gcc/cp/error.c.jj   2019-10-10 01:33:38.187943450 +0200
+++ gcc/cp/error.c      2019-10-14 16:52:27.707101444 +0200
@@ -1648,7 +1648,9 @@ dump_function_decl (cxx_pretty_printer *
         {
           if (DECL_DECLARED_CONCEPT_P (t))
             pp_cxx_ws_string (pp, "concept");
-          else
+         else if (DECL_IMMEDIATE_FUNCTION_P (t))
+           pp_cxx_ws_string (pp, "consteval");
+         else
            pp_cxx_ws_string (pp, "constexpr");
        }
     }
--- gcc/cp/semantics.c.jj       2019-10-14 10:11:32.396100623 +0200
+++ gcc/cp/semantics.c  2019-10-15 12:26:52.389473220 +0200
@@ -4428,7 +4428,7 @@ expand_or_defer_fn_1 (tree fn)
       if (DECL_INTERFACE_KNOWN (fn))
        /* We've already made a decision as to how this function will
           be handled.  */;
-      else if (!at_eof)
+      else if (!at_eof || DECL_IMMEDIATE_FUNCTION_P (fn))
        tentative_decl_linkage (fn);
       else
        import_export_decl (fn);
@@ -4439,6 +4439,7 @@ expand_or_defer_fn_1 (tree fn)
         be emitted; there may be callers in other DLLs.  */
       if (DECL_DECLARED_INLINE_P (fn)
          && !DECL_REALLY_EXTERN (fn)
+         && !DECL_IMMEDIATE_FUNCTION_P (fn)
          && (flag_keep_inline_functions
              || (flag_keep_inline_dllexport
                  && lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))))
@@ -9628,6 +9629,8 @@ finish_decltype_type (tree expr, bool id
       return error_mark_node;
     }
 
+  expr = cxx_eval_consteval (expr);
+
   /* Depending on the resolution of DR 1172, we may later need to distinguish
      instantiation-dependent but not type-dependent expressions so that, say,
      A<decltype(sizeof(T))>::U doesn't require 'typename'.  */
--- gcc/cp/typeck.c.jj  2019-10-12 10:21:30.256263248 +0200
+++ gcc/cp/typeck.c     2019-10-15 12:28:35.530907909 +0200
@@ -1860,10 +1860,11 @@ cxx_alignof_expr (tree e, tsubst_flags_t
 tree
 cxx_sizeof_or_alignof_expr (tree e, enum tree_code op, bool complain)
 {
+  e = cxx_eval_consteval (e);
   if (op == SIZEOF_EXPR)
-    return cxx_sizeof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_sizeof_expr (e, complain ? tf_warning_or_error : tf_none);
   else
-    return cxx_alignof_expr (e, complain? tf_warning_or_error : tf_none);
+    return cxx_alignof_expr (e, complain ? tf_warning_or_error : tf_none);
 }
 
 /*  Build a representation of an expression 'alignas(E).'  Return the
@@ -6177,6 +6178,16 @@ cp_build_addr_expr_1 (tree arg, bool str
     {
       tree stripped_arg = tree_strip_any_location_wrapper (arg);
       if (TREE_CODE (stripped_arg) == FUNCTION_DECL
+         && DECL_IMMEDIATE_FUNCTION_P (stripped_arg)
+         && (current_function_decl == NULL_TREE
+             || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+       {
+         if (complain & tf_error)
+           error ("taking address of an immediate function %qD",
+                  stripped_arg);
+         return error_mark_node;
+       }
+      if (TREE_CODE (stripped_arg) == FUNCTION_DECL
          && !mark_used (stripped_arg, complain) && !(complain & tf_error))
        return error_mark_node;
       val = build_address (arg);
--- gcc/cp/decl.c.jj    2019-10-15 18:34:22.724179075 +0200
+++ gcc/cp/decl.c       2019-10-15 18:50:35.719370678 +0200
@@ -1225,7 +1225,13 @@ validate_constexpr_redeclaration (tree o
     return true;
   if (DECL_DECLARED_CONSTEXPR_P (old_decl)
       == DECL_DECLARED_CONSTEXPR_P (new_decl))
-    return true;
+    {
+      if (TREE_CODE (old_decl) != FUNCTION_DECL)
+       return true;
+      if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+         == DECL_IMMEDIATE_FUNCTION_P (new_decl))
+       return true;
+    }
   if (TREE_CODE (old_decl) == FUNCTION_DECL)
     {
       if (fndecl_built_in_p (old_decl))
@@ -1233,6 +1239,8 @@ validate_constexpr_redeclaration (tree o
          /* Hide a built-in declaration.  */
          DECL_DECLARED_CONSTEXPR_P (old_decl)
            = DECL_DECLARED_CONSTEXPR_P (new_decl);
+         if (DECL_IMMEDIATE_FUNCTION_P (new_decl))
+           SET_DECL_IMMEDIATE_FUNCTION_P (old_decl);
          return true;
        }
       /* 7.1.5 [dcl.constexpr]
@@ -1242,9 +1250,14 @@ validate_constexpr_redeclaration (tree o
          && DECL_TEMPLATE_SPECIALIZATION (new_decl))
        return true;
 
+      const char *kind = "constexpr";
+      if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+         || DECL_IMMEDIATE_FUNCTION_P (new_decl))
+       kind = "consteval";
       error_at (DECL_SOURCE_LOCATION (new_decl),
-               "redeclaration %qD differs in %<constexpr%> "
-               "from previous declaration", new_decl);
+               "redeclaration %qD differs in %qs "
+               "from previous declaration", new_decl,
+               kind);
       inform (DECL_SOURCE_LOCATION (old_decl),
              "previous declaration %qD", old_decl);
       return false;
@@ -5034,12 +5047,15 @@ check_tag_decl (cp_decl_specifier_seq *d
       else if (saw_typedef)
        warning_at (declspecs->locations[ds_typedef], 0,
                    "%<typedef%> was ignored in this declaration");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constexpr))
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
         error_at (declspecs->locations[ds_constexpr],
-                 "%<constexpr%> cannot be used for type declarations");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constinit))
+                 "%qs cannot be used for type declarations", "constexpr");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
        error_at (declspecs->locations[ds_constinit],
-                 "%<constinit%> cannot be used for type declarations");
+                 "%qs cannot be used for type declarations", "constinit");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_consteval))
+       error_at (declspecs->locations[ds_consteval],
+                 "%qs cannot be used for type declarations", "consteval");
     }
 
   if (declspecs->attributes && warn_attributes && declared_type)
@@ -5397,11 +5413,14 @@ start_decl (const cp_declarator *declara
       bool ok = false;
       if (CP_DECL_THREAD_LOCAL_P (decl))
        error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD declared %<thread_local%> in %<constexpr%> function",
-                 decl);
+                 "%qD declared %<thread_local%> in %qs function", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
       else if (TREE_STATIC (decl))
        error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD declared %<static%> in %<constexpr%> function", decl);
+                 "%qD declared %<static%> in %qs function", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
       else
        ok = true;
       if (!ok)
@@ -6559,6 +6578,9 @@ check_initializer (tree decl, tree init,
     /* There is no way to make a variable-sized class type in GNU C++.  */
     gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
 
+  if (init && TREE_STATIC (decl))
+    init = cxx_eval_consteval (init);
+
   if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
     {
       int init_len = CONSTRUCTOR_NELTS (init);
@@ -9154,6 +9176,15 @@ grokfndecl (tree ctype,
          }
     }
 
+  /* FIXME: For now.  */
+  if (virtualp && (inlinep & 8) != 0)
+    {
+      sorry_at (DECL_SOURCE_LOCATION (decl),
+               "%<virtual%> %<consteval%> method %qD not supported yet",
+               decl);
+      inlinep &= ~8;
+    }
+
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
@@ -9201,7 +9232,10 @@ grokfndecl (tree ctype,
                  "cannot declare %<::main%> to be inline");
       if (inlinep & 2)
        error_at (declspecs->locations[ds_constexpr],
-                 "cannot declare %<::main%> to be %<constexpr%>");
+                 "cannot declare %<::main%> to be %qs", "constexpr");
+      if (inlinep & 8)
+       error_at (declspecs->locations[ds_consteval],
+                 "cannot declare %<::main%> to be %qs", "consteval");
       if (!publicp)
        error_at (location, "cannot declare %<::main%> to be static");
       inlinep = 0;
@@ -9240,6 +9274,11 @@ grokfndecl (tree ctype,
     }
   if (inlinep & 2)
     DECL_DECLARED_CONSTEXPR_P (decl) = true;
+  else if (inlinep & 8)
+    {
+      DECL_DECLARED_CONSTEXPR_P (decl) = true;
+      SET_DECL_IMMEDIATE_FUNCTION_P (decl);
+    }
 
   // If the concept declaration specifier was found, check
   // that the declaration satisfies the necessary requirements.
@@ -10604,6 +10643,7 @@ grokdeclarator (const cp_declarator *dec
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
+  bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
   tree reqs = NULL_TREE;
@@ -10876,17 +10916,31 @@ grokdeclarator (const cp_declarator *dec
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
+  if (consteval_p && constexpr_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+               "both %qs and %qs specified", "constexpr", "consteval");
+      return error_mark_node;
+    }
+
   if (concept_p && typedef_p)
     {
       error_at (declspecs->locations[ds_concept],
-               "%<concept%> cannot appear in a typedef declaration");
+               "%qs cannot appear in a typedef declaration", "concept");
       return error_mark_node;
     }
 
   if (constexpr_p && typedef_p)
     {
       error_at (declspecs->locations[ds_constexpr],
-               "%<constexpr%> cannot appear in a typedef declaration");
+               "%qs cannot appear in a typedef declaration", "constexpr");
+      return error_mark_node;
+    }
+
+  if (consteval_p && typedef_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+               "%qs cannot appear in a typedef declaration", "consteval");
       return error_mark_node;
     }
 
@@ -11292,21 +11346,31 @@ grokdeclarator (const cp_declarator *dec
 
       /* Function parameters cannot be concept. */
       if (concept_p)
-       error_at (declspecs->locations[ds_concept],
-                 "a parameter cannot be declared %<concept%>");
+       {
+         error_at (declspecs->locations[ds_concept],
+                   "a parameter cannot be declared %qs", "concept");
+         concept_p = 0;
+         constexpr_p = 0;
+       }
       /* Function parameters cannot be constexpr.  If we saw one, moan
          and pretend it wasn't there.  */
       else if (constexpr_p)
         {
           error_at (declspecs->locations[ds_constexpr],
-                   "a parameter cannot be declared %<constexpr%>");
+                   "a parameter cannot be declared %qs", "constexpr");
           constexpr_p = 0;
         }
-      else if (constinit_p)
+      if (constinit_p)
        {
          error_at (declspecs->locations[ds_constinit],
-                   "a parameter cannot be declared %<constinit%>");
-         constexpr_p = 0;
+                   "a parameter cannot be declared %qs", "constinit");
+         constinit_p = 0;
+       }
+      if (consteval_p)
+       {
+         error_at (declspecs->locations[ds_consteval],
+                   "a parameter cannot be declared %qs", "consteval");
+         consteval_p = 0;
        }
     }
 
@@ -11329,9 +11393,12 @@ grokdeclarator (const cp_declarator *dec
       if (typedef_p)
        error_at (declspecs->locations[ds_typedef],
                  "structured binding declaration cannot be %qs", "typedef");
-      if (constexpr_p)
+      if (constexpr_p && !concept_p)
        error_at (declspecs->locations[ds_constexpr], "structured "
                  "binding declaration cannot be %qs", "constexpr");
+      if (consteval_p)
+       error_at (declspecs->locations[ds_consteval], "structured "
+                 "binding declaration cannot be %qs", "consteval");
       if (thread_p && cxx_dialect < cxx2a)
        pedwarn (declspecs->locations[ds_thread], 0,
                 "structured binding declaration can be %qs only in "
@@ -11391,6 +11458,7 @@ grokdeclarator (const cp_declarator *dec
       inlinep = 0;
       typedef_p = 0;
       constexpr_p = 0;
+      consteval_p = 0;
       concept_p = 0;
       if (storage_class != sc_static)
        {
@@ -12788,7 +12856,7 @@ grokdeclarator (const cp_declarator *dec
                 if (concept_p)
                   {
                     error_at (declspecs->locations[ds_concept],
-                             "a destructor cannot be %<concept%>");
+                             "a destructor cannot be %qs", "concept");
                     return error_mark_node;
                   }
                if (constexpr_p && cxx_dialect < cxx2a)
@@ -12798,6 +12866,12 @@ grokdeclarator (const cp_declarator *dec
                              " with %<-std=c++2a%> or %<-std=gnu++2a%>");
                    return error_mark_node;
                  }
+               if (consteval_p)
+                 {
+                   error_at (declspecs->locations[ds_consteval],
+                             "a destructor cannot be %qs", "consteval");
+                   return error_mark_node;
+                 }
              }
            else if (sfk == sfk_constructor && friendp && !ctype)
              {
@@ -12819,6 +12893,14 @@ grokdeclarator (const cp_declarator *dec
                          "a concept cannot be a member function");
                concept_p = false;
              }
+           else if (consteval_p
+                    && identifier_p (unqualified_id)
+                    && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+             {
+               error_at (declspecs->locations[ds_consteval],
+                         "%qD cannot be %qs", unqualified_id, "consteval");
+               consteval_p = false;
+             }
 
            if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
              {
@@ -12849,7 +12931,8 @@ grokdeclarator (const cp_declarator *dec
                               reqs,
                               virtualp, flags, memfn_quals, rqual, raises,
                               friendp ? -1 : 0, friendp, publicp,
-                               inlinep | (2 * constexpr_p) | (4 * concept_p),
+                              inlinep | (2 * constexpr_p) | (4 * concept_p)
+                                      | (8 * consteval_p),
                               initialized == SD_DELETED, sfk,
                               funcdef_flag, late_return_type_p,
                               template_count, in_namespace,
@@ -12951,8 +13034,8 @@ grokdeclarator (const cp_declarator *dec
                set_linkage_for_static_data_member (decl);
                if (concept_p)
                  error_at (declspecs->locations[ds_concept],
-                           "static data member %qE declared %<concept%>",
-                           unqualified_id);
+                           "static data member %qE declared %qs",
+                           unqualified_id, "concept");
                else if (constexpr_p && !initialized)
                  {
                    error_at (DECL_SOURCE_LOCATION (decl),
@@ -12960,6 +13043,10 @@ grokdeclarator (const cp_declarator *dec
                              "have an initializer", decl);
                    constexpr_p = false;
                  }
+               if (consteval_p)
+                 error_at (declspecs->locations[ds_consteval],
+                           "static data member %qE declared %qs",
+                           unqualified_id, "consteval");
 
                if (inlinep)
                  mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -12984,23 +13071,34 @@ grokdeclarator (const cp_declarator *dec
            else
              {
                if (concept_p)
-                 error_at (declspecs->locations[ds_concept],
-                           "non-static data member %qE declared %<concept%>",
-                           unqualified_id);
-                else if (constexpr_p)
+                 {
+                   error_at (declspecs->locations[ds_concept],
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "concept");
+                   concept_p = false;
+                   constexpr_p = false;
+                 }
+               else if (constexpr_p)
                  {
                    error_at (declspecs->locations[ds_constexpr],
-                             "non-static data member %qE declared "
-                             "%<constexpr%>", unqualified_id);
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "constexpr");
                    constexpr_p = false;
                  }
-               else if (constinit_p)
+               if (constinit_p)
                  {
                    error_at (declspecs->locations[ds_constinit],
-                             "non-static data member %qE declared "
-                             "%<constinit%>", unqualified_id);
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "constinit");
                    constinit_p = false;
                  }
+               if (consteval_p)
+                 {
+                   error_at (declspecs->locations[ds_consteval],
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "consteval");
+                   consteval_p = false;
+                 }
                decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type);
                DECL_NONADDRESSABLE_P (decl) = bitfield;
                if (bitfield && !unqualified_id)
@@ -13106,6 +13204,14 @@ grokdeclarator (const cp_declarator *dec
                sfk = sfk_none;
              }
          }
+       if (consteval_p
+           && identifier_p (unqualified_id)
+           && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+         {
+           error_at (declspecs->locations[ds_consteval],
+                     "%qD cannot be %qs", unqualified_id, "consteval");
+           consteval_p = false;
+         }
 
        /* Record whether the function is public.  */
        publicp = (ctype != NULL_TREE
@@ -13116,7 +13222,8 @@ grokdeclarator (const cp_declarator *dec
                            reqs, virtualp, flags, memfn_quals, rqual, raises,
                           1, friendp,
                           publicp,
-                           inlinep | (2 * constexpr_p) | (4 * concept_p),
+                          inlinep | (2 * constexpr_p) | (4 * concept_p)
+                                  | (8 * consteval_p),
                           initialized == SD_DELETED,
                            sfk,
                            funcdef_flag,
@@ -13209,6 +13316,12 @@ grokdeclarator (const cp_declarator *dec
                      "is not a definition", decl);
            constexpr_p = false;
          }
+       if (consteval_p)
+         {
+           error_at (DECL_SOURCE_LOCATION (decl),
+                     "a variable cannot be declared %<consteval%>");
+           consteval_p = false;
+         }
 
        if (inlinep)
          mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -16469,6 +16582,9 @@ finish_function (bool inline_p)
          || is_valid_constexpr_fn (fndecl, /*complain*/false))
         && potential_constant_expression (DECL_SAVED_TREE (fndecl)));
 
+  if (!DECL_IMMEDIATE_FUNCTION_P (fndecl))
+    DECL_SAVED_TREE (fndecl) = cxx_eval_consteval (DECL_SAVED_TREE (fndecl));
+
   /* Save constexpr function body before it gets munged by
      the NRV transformation.   */
   maybe_save_function_definition (fndecl);
@@ -16478,7 +16594,7 @@ finish_function (bool inline_p)
     invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
 
   /* Perform delayed folding before NRV transformation.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_fold_function (fndecl);
 
   /* Set up the named return value optimization, if we can.  Candidate
@@ -16595,7 +16711,7 @@ finish_function (bool inline_p)
     do_warn_unused_parameter (fndecl);
 
   /* Genericize before inlining.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_genericize (fndecl);
 
   /* We're leaving the context of this function, so zap cfun.  It's still in
--- gcc/cp/constexpr.c.jj       2019-10-12 10:21:30.258263218 +0200
+++ gcc/cp/constexpr.c  2019-10-15 15:33:18.390730126 +0200
@@ -1022,8 +1022,10 @@ struct constexpr_global_ctx {
   /* Heap VAR_DECLs created during the evaluation of the outermost constant
      expression.  */
   auto_vec<tree, 16> heap_vars;
+  /* True if evaluating a call to consteval function.  */
+  bool in_consteval;
   /* Constructor.  */
-  constexpr_global_ctx () : constexpr_ops_count (0) {}
+  constexpr_global_ctx () : constexpr_ops_count (0), in_consteval (false) {}
 };
 
 /* The constexpr expansion context.  CALL is the current function
@@ -1663,6 +1665,20 @@ cxx_eval_call_expression (const constexp
            }
        }
     }
+  else if (DECL_IMMEDIATE_FUNCTION_P (fun)
+          && !ctx->global->in_consteval
+          && (current_function_decl == NULL_TREE
+              || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    {
+      tree c = cxx_constant_value (t, NULL_TREE);
+      if (c == t || c == error_mark_node)
+       {
+         *non_constant_p = true;
+         return t;
+       }
+      return cxx_eval_constant_expression (ctx, c, lval, non_constant_p,
+                                          overflow_p);
+    }
   if (TREE_CODE (fun) != FUNCTION_DECL)
     {
       if (!ctx->quiet && !*non_constant_p)
@@ -5641,6 +5657,17 @@ find_heap_var_refs (tree *tp, int *walk_
   return NULL_TREE;
 }
 
+/* Find immediate function decls in *TP if any.  */
+
+static tree
+find_immediate_fndecl (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == FUNCTION_DECL
+      && DECL_IMMEDIATE_FUNCTION_P (*tp))
+    return *tp;
+  return NULL_TREE;
+}
+
 /* ALLOW_NON_CONSTANT is false if T is required to be a constant expression.
    STRICT has the same sense as for constant_value_1: true if we only allow
    conforming C++ constant expressions, or false if we want a constant value
@@ -5675,7 +5702,26 @@ cxx_eval_outermost_constant_expr (tree t
        /* Used for destructors of array elements.  */
        type = TREE_TYPE (object);
       else
-       return t;
+       {
+         if (cxx_dialect < cxx2a)
+           return t;
+         if (TREE_CODE (t) != CALL_EXPR && TREE_CODE (t) != AGGR_INIT_EXPR)
+           return t;
+         /* Calls to immediate functions returning void need to be
+            evaluated.  */
+         tree fndecl = cp_get_callee_fndecl_nofold (t);
+         if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
+           return t;
+         else
+           global_ctx.in_consteval = true;
+       }
+    }
+  else if (cxx_dialect >= cxx2a
+          && (TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == AGGR_INIT_EXPR))
+    {
+      tree fndecl = cp_get_callee_fndecl_nofold (t);
+      if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
+       global_ctx.in_consteval = true;
     }
   if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
     {
@@ -5776,6 +5822,25 @@ cxx_eval_outermost_constant_expr (tree t
          }
     }
 
+  /* Check that immediate invocation does not return an expression referencing
+     any immediate function decls.  They need to be allowed while parsing
+     immediate functions, but can't leak outside of them.  */
+  if (global_ctx.in_consteval
+      && t != r
+      && (current_function_decl == NULL_TREE
+         || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl)))
+    if (tree immediate_fndecl
+       = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
+                                          NULL))
+    {
+      if (!allow_non_constant && !non_constant_p)
+       error_at (cp_expr_loc_or_input_loc (t),
+                 "immediate evaluation returns address of immediate "
+                 "function %qD", immediate_fndecl);
+      r = t;
+      non_constant_p = true;
+    }
+
   /* Technically we should check this for all subexpressions, but that
      runs into problems with our internal representation of pointer
      subtraction and the 5.19 rules are still in flux.  */
@@ -5865,6 +5930,63 @@ cxx_constant_dtor (tree t, tree decl)
   cxx_eval_outermost_constant_expr (t, false, true, true, true, decl);
 }
 
+static tree
+fold_non_dependent_expr_template (tree, tsubst_flags_t, bool, bool);
+
+/* Helper function for cxx_eval_consteval.  Find calls to immediate
+   functions in *TP and evaluate them.  */
+
+static tree
+cxx_eval_consteval_r (tree *tp, int */*walk_subtrees*/, void */*data*/)
+{
+  if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
+    {
+      tree callee = cp_get_callee (*tp);
+      if (processing_template_decl
+         && callee
+         && TREE_CODE (callee) != FUNCTION_DECL
+         && (TREE_TYPE (callee) == NULL_TREE
+             || !INDIRECT_TYPE_P (TREE_TYPE (callee))))
+       return NULL_TREE;
+      callee = cp_get_fndecl_from_callee (callee, false);
+      if (callee && DECL_IMMEDIATE_FUNCTION_P (callee))
+       {
+         if (processing_template_decl)
+           fold_non_dependent_expr_template (*tp, tf_warning_or_error,
+                                             /*allow_non_constant*/false,
+                                             /*manifestly_const_eval=*/ true);
+         else
+           {
+             int saved_errorcount = errorcount;
+             tree t = cxx_constant_value (*tp, NULL_TREE);
+             if (t != *tp)
+               *tp = t;
+             else
+               {
+                 /* Error recovery, make sure we don't diagnose it multiple
+                    times.  */
+                 gcc_assert (errorcount > saved_errorcount);
+                 if (VOID_TYPE_P (TREE_TYPE (*tp)))
+                   *tp = void_node;
+                 else
+                   *tp = build_zero_cst (t);
+               }
+           }
+       }
+    }
+  return NULL_TREE;
+}
+
+/* Evaluate calls to immediate functions in T.  */
+
+tree
+cxx_eval_consteval (tree t)
+{
+  if (cxx_dialect >= cxx2a)
+    cp_walk_tree_without_duplicates (&t, cxx_eval_consteval_r, NULL);
+  return t;
+}
+
 /* Helper routine for fold_simple function.  Either return simplified
    expression T, otherwise NULL_TREE.
    In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
@@ -6016,6 +6138,7 @@ clear_cv_and_fold_caches (bool sat /*= t
 
 static tree
 fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
+                                 bool allow_non_constant,
                                  bool manifestly_const_eval)
 {
   gcc_assert (processing_template_decl);
@@ -6035,7 +6158,7 @@ fold_non_dependent_expr_template (tree t
          return t;
        }
 
-      tree r = cxx_eval_outermost_constant_expr (t, true, true,
+      tree r = cxx_eval_outermost_constant_expr (t, allow_non_constant, true,
                                                 manifestly_const_eval,
                                                 false, NULL_TREE);
       /* cp_tree_equal looks through NOPs, so allow them.  */
@@ -6080,6 +6203,7 @@ fold_non_dependent_expr (tree t,
 
   if (processing_template_decl)
     return fold_non_dependent_expr_template (t, complain,
+                                            /*allow_non_constant*/true,
                                             manifestly_const_eval);
 
   return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
@@ -6099,6 +6223,7 @@ fold_non_dependent_init (tree t,
   if (processing_template_decl)
     {
       t = fold_non_dependent_expr_template (t, complain,
+                                           /*allow_non_constant*/true,
                                            manifestly_const_eval);
       /* maybe_constant_init does this stripping, so do it here too.  */
       if (TREE_CODE (t) == TARGET_EXPR)
--- gcc/cp/method.c.jj  2019-10-12 10:21:30.257263232 +0200
+++ gcc/cp/method.c     2019-10-14 18:23:24.258313542 +0200
@@ -2256,8 +2256,9 @@ defaulted_late_check (tree fn)
       if (!CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
        {
          error ("explicitly defaulted function %q+D cannot be declared "
-                "%qs because the implicit declaration is not %qs:",
-                fn, "constexpr", "constexpr");
+                "%qs because the implicit declaration is not %qs:", fn,
+                DECL_IMMEDIATE_FUNCTION_P (fn) ? "consteval" : "constexpr",
+                "constexpr");
          explain_implicit_non_constexpr (fn);
        }
       DECL_DECLARED_CONSTEXPR_P (fn) = false;
--- gcc/cp/except.c.jj  2019-06-25 08:57:57.706484715 +0200
+++ gcc/cp/except.c     2019-10-15 13:56:59.833413107 +0200
@@ -1191,6 +1191,8 @@ finish_noexcept_expr (tree expr, tsubst_
   if (expr == error_mark_node)
     return error_mark_node;
 
+  expr = cxx_eval_consteval (expr);
+
   if (processing_template_decl)
     return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
 
--- gcc/cp/lambda.c.jj  2019-10-10 01:33:38.284941998 +0200
+++ gcc/cp/lambda.c     2019-10-15 13:41:52.372183503 +0200
@@ -1189,6 +1189,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = build_this_parm (fn, fntype, TYPE_QUAL_CONST);
 
   if (nested_def)
@@ -1221,6 +1224,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = fn_args;
   for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
--- gcc/testsuite/g++.dg/cpp2a/consteval1.C.jj  2019-10-14 16:52:27.711101384 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval1.C     2019-10-14 16:52:27.711101384 
+0200
@@ -0,0 +1,37 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+extern "C" void abort ();
+constexpr int f0 (int n) { return n; }
+consteval int f1 (int n) { return f0 (n) * n; }
+consteval int f2 (int n) { return f1 (n); }
+consteval bool f3 () { return std::is_constant_evaluated (); }
+struct S { constexpr S (int x) : s (x) {} consteval int m1 (int n) const; int 
s; };
+consteval int
+S::m1 (int n) const
+{
+  n += s;
+  return n;
+}
+
+constexpr int a = 2;
+int b = f1 (a);
+int c = f2 (f1 (a));
+bool d = f3 ();
+constexpr S e = 41;
+int f = e.m1 (1);
+
+int
+main ()
+{
+  if (b != 4 || c != 16 || !d || f != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval2.C.jj  2019-10-14 16:52:27.712101369 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval2.C     2019-10-14 16:52:27.712101369 
+0200
@@ -0,0 +1,17 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+consteval int baz (int (*fn) () = bar ()) { return fn (); }
+constexpr int a = baz ();
+static_assert (a == 42);
+int b = baz ();
+
+int
+main ()
+{
+  if (b != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval3.C.jj  2019-10-14 16:52:27.712101369 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval3.C     2019-10-15 16:28:25.253572602 
+0200
@@ -0,0 +1,62 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { S () : a (0), b (1) {} int a, b; };
+int f1 ();             // { dg-message "previous declaration 'int f1\\(\\)'" }
+consteval int f1 ();   // { dg-error "redeclaration 'consteval int f1\\(\\)' 
differs in 'consteval' from previous declaration" }
+consteval int f2 ();   // { dg-message "previous declaration 'consteval int 
f2\\(\\)'" }
+int f2 ();             // { dg-error "redeclaration 'int f2\\(\\)' differs in 
'consteval' from previous declaration" }
+constexpr int f3 ();   // { dg-message "previous declaration 'constexpr int 
f3\\(\\)'" }
+consteval int f3 ();   // { dg-error "redeclaration 'consteval int f3\\(\\)' 
differs in 'consteval' from previous declaration" }
+consteval int f4 ();   // { dg-message "previous declaration 'consteval int 
f4\\(\\)'" }
+constexpr int f4 ();   // { dg-error "redeclaration 'constexpr int f4\\(\\)' 
differs in 'consteval' from previous declaration" }
+typedef consteval int cint;    // { dg-error "'consteval' cannot appear in a 
typedef declaration" }
+consteval struct T { int i; }; // { dg-error "'consteval' cannot be used for 
type declarations" }
+consteval int a = 5;   // { dg-error "a variable cannot be declared 
'consteval'" }
+consteval auto [ b, c ] = S ();                // { dg-error "structured 
binding declaration cannot be 'consteval'" }
+int f5 (consteval int x) { return x; } // { dg-error "a parameter cannot be 
declared 'consteval'" }
+consteval int f6 (int x) { return x; }
+int d = 6;             // { dg-message "'int d' is not const" }
+int e = f6 (d);                // { dg-error "the value of 'd' is not usable 
in a constant expression" }
+constexpr int f7 (int x) { return f6 (x); }    // { dg-error "'x' is not a 
constant expression" }
+constexpr int f = f7 (5);      // { dg-error "" }
+using fnptr = int (int);
+fnptr *g = f6;         // { dg-error "taking address of an immediate function 
'consteval int f6\\(int\\)'" }
+int f8 (fnptr *);
+int h = f8 (f6);       // { dg-error "taking address of an immediate function 
'consteval int f6\\(int\\)'" }
+consteval constexpr int f9 () { return 0; }    // { dg-error "both 'constexpr' 
and 'consteval' specified" }
+constexpr consteval int f10 () { return 0; }   // { dg-error "both 'constexpr' 
and 'consteval' specified" }
+consteval consteval int f11 () { return 0; }   // { dg-error "duplicate 
'consteval'" }
+struct U { consteval ~U () {} };       // { dg-error "a destructor cannot be 
'consteval'" }
+struct V { consteval int v = 5; };     // { dg-error "non-static data member 
'v' declared 'consteval'" }
+struct W { consteval static int w; };  // { dg-error "static data member 'w' 
declared 'consteval'" }
+int i = sizeof (&f6);                  // { dg-error "taking address of an 
immediate function 'consteval int f6\\(int\\)'" }
+using j = decltype (&f6);              // { dg-error "taking address of an 
immediate function 'consteval int f6\\(int\\)'" }
+int k = sizeof (f6 (d));               // { dg-error "the value of 'd' is not 
usable in a constant expression" }
+using l = decltype (f6 (d));           // { dg-error "the value of 'd' is not 
usable in a constant expression" }
+bool m = noexcept (f6 (d));            // { dg-error "the value of 'd' is not 
usable in a constant expression" }
+namespace std {
+using size_t = decltype (sizeof (0));
+}
+consteval void* operator new (std::size_t);    // { dg-error "'operator new' 
cannot be 'consteval'" }
+consteval void operator delete (void *, std::size_t) noexcept; // { dg-error 
"'operator delete' cannot be 'consteval'" }
+consteval void operator delete[] (void *) noexcept;    // { dg-error 
"'operator delete \\\[\\\]' cannot be 'consteval'" }
+struct X {
+  static consteval void* operator new (std::size_t);   // { dg-error 
"'operator new' cannot be 'consteval'" }
+  static consteval void operator delete (void *, std::size_t) noexcept;        
// { dg-error "'operator delete' cannot be 'consteval'" }
+  consteval static void operator delete[] (void *) noexcept;   // { dg-error 
"'operator delete \\\[\\\]' cannot be 'consteval'" }
+};
+consteval int main () { return 0; }    // { dg-error "cannot declare '::main' 
to be 'consteval'" }
+struct A { A (); int a; };             // { dg-message "defaulted constructor 
calls non-'constexpr' 'A::A\\(\\)'" }
+struct B { constexpr B () : b (0) {} int b; };
+struct C { A a; consteval C () = default; };   // { dg-error "explicitly 
defaulted function 'consteval C::C\\(\\)' cannot be declared 'consteval' 
because the implicit declaration is not 'constexpr'" }
+struct D { B b; consteval D () = default; };
+template <class T> consteval T f12 (T x) { return x; }
+template consteval float f12 (float x); // { dg-error "explicit instantiation 
shall not use 'consteval' specifier" }
+consteval int
+f13 (int x)
+{
+  static int a = 5;            // { dg-error "'a' declared 'static' in 
'consteval' function" }
+  thread_local int b = 6;      // { dg-error "'b' declared 'thread_local' in 
'consteval' function" }
+  return x;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval4.C.jj  2019-10-14 16:52:27.712101369 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval4.C     2019-10-14 16:52:27.712101369 
+0200
@@ -0,0 +1,29 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+extern "C" void abort ();
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+int
+main ()
+{
+  constexpr int a = 5;
+  auto b = [] (int n) consteval { return n + a + std::is_constant_evaluated 
(); };
+  int c = b (4);
+  if (c != 10)
+    abort ();
+  auto d = [] () consteval { return a + std::is_constant_evaluated (); };
+  int e = d ();
+  if (e != 6)
+    abort ();
+  constexpr int f = d ();
+  if (f != 6)
+    abort ();
+  static_assert (d () == 6);
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval5.C.jj  2019-10-14 16:52:27.712101369 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval5.C     2019-10-14 16:52:27.712101369 
+0200
@@ -0,0 +1,42 @@
+// { dg-do run }
+// { dg-options "-std=c++2a" }
+
+namespace std {
+  constexpr inline bool
+  is_constant_evaluated () noexcept
+  {
+    return __builtin_is_constant_evaluated ();
+  }
+}
+
+extern "C" void abort ();
+template <int N>
+constexpr int f0 (int n) { return n + N; }
+template <int N>
+consteval int f1 (int n) { return f0<N> (n) * n + N; }
+template <int N>
+consteval int f2 (int n) { return f1<N> (n); }
+template <int N>
+consteval bool f3 () { return std::is_constant_evaluated () + N; }
+struct S { constexpr S (int x) : s (x) {} template <int N> consteval int m1 
(int n) const; int s; };
+template <int N>
+consteval int
+S::m1 (int n) const
+{
+  n += s + N;
+  return n;
+}
+
+constexpr int a = 2;
+int b = f1<0> (a);
+int c = f2<0> (f1<0> (a));
+bool d = f3<0> ();
+constexpr S e = 41;
+int f = e.m1<0> (1);
+
+int
+main ()
+{
+  if (b != 4 || c != 16 || !d || f != 42)
+    abort ();
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval6.C.jj  2019-10-14 16:52:27.712101369 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval6.C     2019-10-14 16:52:27.712101369 
+0200
@@ -0,0 +1,26 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct A {
+  constexpr A () {}
+  A (A const&) = delete;       // { dg-message "declared here" }
+};
+
+template<typename T>
+constexpr void
+foo ()
+{
+  T t;
+  T u = t;
+}
+
+template<typename T>
+consteval void
+bar ()
+{
+  T t;
+  T u = t;     // { dg-error "use of deleted function" }
+}
+
+using B = decltype (foo<A> ());
+using C = decltype (bar<A> ());        // { dg-message "required from here" }
--- gcc/testsuite/g++.dg/cpp2a/consteval7.C.jj  2019-10-14 16:52:27.726101156 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval7.C     2019-10-15 11:32:51.815658571 
+0200
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo () { return 42; }
+consteval auto bar () { return foo; }
+constexpr auto a = bar ();     // { dg-error "immediate evaluation returns 
address of immediate function 'consteval int foo\\(\\)'" }
+struct S { int b; int (*c) (); };
+consteval S baz () { return { 5, foo }; }
+consteval int qux () { S s = baz (); return s.b + s.c (); }
+consteval int quux () { constexpr S s = baz (); return s.b + s.c (); }
+constexpr auto d = baz ();     // { dg-error "immediate evaluation returns 
address of immediate function 'consteval int foo\\(\\)'" }
+constexpr auto e = qux ();
+constexpr auto f = quux ();
--- gcc/testsuite/g++.dg/cpp2a/consteval8.C.jj  2019-10-15 10:29:50.229065304 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval8.C     2019-10-15 10:30:33.032415274 
+0200
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } int a, b; };
+S c;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  return S ().a;
+}
--- gcc/testsuite/g++.dg/cpp2a/consteval9.C.jj  2019-10-15 13:09:39.781510537 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval9.C     2019-10-15 13:11:52.785492131 
+0200
@@ -0,0 +1,31 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar (int i) { if (i != 1) throw 1; return 0; }   // { dg-error 
"is not a constant expression" }
+
+template <int N>
+void foo ()
+{
+  int a = bar (N);
+}
+
+template <int N>
+void qux ()
+{
+  int a = bar (N);     // { dg-message "in 'constexpr' expansion of 
'bar\\(2\\)'" }
+}
+
+template <int N>
+void quux ()
+{
+  int a = bar (5);     // { dg-message "in 'constexpr' expansion of 
'bar\\(5\\)'" }
+}
+
+void
+baz ()
+{
+  foo<1> ();
+  qux<2> ();
+}
+
+int a = bar (2);       // { dg-message "in 'constexpr' expansion of 
'bar\\(2\\)'" }
--- gcc/testsuite/g++.dg/cpp2a/consteval10.C.jj 2019-10-15 13:12:24.741007195 
+0200
+++ gcc/testsuite/g++.dg/cpp2a/consteval10.C    2019-10-15 13:13:29.032031549 
+0200
@@ -0,0 +1,3 @@
+// { dg-do compile }
+
+consteval int bar (void) { return 0; } // { dg-error "'consteval' does not 
name a type" "" { target c++17_down } }
--- gcc/testsuite/g++.dg/ext/consteval1.C.jj    2019-10-15 14:06:18.667933180 
+0200
+++ gcc/testsuite/g++.dg/ext/consteval1.C       2019-10-15 15:33:18.391730111 
+0200
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int foo (int x) { return x; }
+int d = 6;                     // { dg-message "'int d' is not const" }
+bool e = __builtin_has_attribute (foo (d), packed);    // { dg-error "the 
value of 'd' is not usable in a constant expression" }

        Jakub

Reply via email to