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

From-SVN: r277733

32 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/constexpr.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/error.c
gcc/cp/init.c
gcc/cp/lambda.c
gcc/cp/method.c
gcc/cp/name-lookup.h
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp2a/consteval1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval10.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval11.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval14.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval5.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval6.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval8.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/consteval9.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/consteval1.C [new file with mode: 0644]

index 372f452dc2d2a574e6ca8f6df2cb2258be91669c..9bc219049a383cb785cc8f8ae2b9fdaa2b027240 100644 (file)
@@ -1,3 +1,9 @@
+2019-11-02  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c++/88335 - Implement P1073R3: Immediate functions
+       * c-common.h (enum rid): Add RID_CONSTEVAL.
+       * c-common.c (c_common_reswords): Add consteval.
+
 2019-10-30  Nathan Sidwell  <nathan@acm.org>
 
        * c-cppbuiltin.c (c_cpp_builtins): Add 'L' suffix to feature
index 79c047c4730d6710e7ea638fa0ef913e18881cde..743ef04918df718d17b17feb7addca73d6c9da0e 100644 (file)
@@ -459,6 +459,7 @@ const struct c_common_resword c_common_reswords[] =
   { "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 },
index 42426ef6e1d58e382e58d401dbbab4fd24910b00..5a24a7eb2f76afcee8f8cce2d9c6c6edc09a2434 100644 (file)
@@ -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,
index 50da698107d12cd3ac9bb478e0dfca9f22e23a93..06a4e31578f8cc4bfd661021df2bed3b829b8181 100644 (file)
@@ -1,5 +1,70 @@
 2019-11-02  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/88335 - Implement P1073R3: Immediate functions
+       * cp-tree.h (struct lang_decl_fn): Add immediate_fn_p bit.
+       (DECL_IMMEDIATE_FUNCTION_P, SET_DECL_IMMEDIATE_FUNCTION_P): Define.
+       (enum cp_decl_spec): Add ds_consteval.
+       (fold_non_dependent_expr): Add another tree argument defaulted to
+       NULL_TREE.
+       * name-lookup.h (struct cp_binding_level): Add immediate_fn_ctx_p
+       member.
+       * parser.c (cp_keyword_starts_decl_specifier_p): Adjust comments
+       for C++11 and C++20 specifiers.  Handle RID_CONSTEVAL.
+       (CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR): Adjust comment.
+       (CP_PARSER_FLAGS_CONSTEVAL): New.
+       (cp_parser_skip_balanced_tokens): New forward declaration.
+       (cp_parser_lambda_declarator_opt): Handle ds_consteval.  Set
+       current_binding_level->immediate_fn_ctx_p before parsing parameter
+       list if decl-specifier-seq contains consteval specifier.
+       (cp_parser_decl_specifier_seq): Handle RID_CONSTEVAL.
+       (cp_parser_explicit_instantiation): Diagnose explicit instantiation
+       with consteval specifier.
+       (cp_parser_init_declarator): For consteval or into flags
+       CP_PARSER_FLAGS_CONSTEVAL.
+       (cp_parser_direct_declarator): If CP_PARSER_FLAGS_CONSTEVAL, set
+       current_binding_level->immediate_fn_ctx_p in the sk_function_parms
+       scope.
+       (set_and_check_decl_spec_loc): Add consteval entry, formatting fix.
+       * call.c (build_addr_func): For direct calls to immediate functions
+       use build_address rather than decay_conversion.
+       (build_over_call): Evaluate immediate function invocations.
+       * error.c (dump_function_decl): Handle DECL_IMMEDIATE_FUNCTION_P.
+       * semantics.c (expand_or_defer_fn_1): Use tentative linkage and don't
+       call mark_needed for immediate functions.
+       * typeck.c (cxx_sizeof_or_alignof_expr): Likewise.  Formatting fix.
+       (cp_build_addr_expr_1): Reject taking address of immediate function
+       outside of immediate function.
+       * decl.c (validate_constexpr_redeclaration): Diagnose consteval
+       vs. non-consteval or vice versa redeclaration.  Use
+       SET_DECL_IMMEDIATE_FUNCTION_P if new_decl is immediate function.
+       (check_tag_decl): Use %qs with keyword string to simplify translation.
+       Handle ds_consteval.
+       (start_decl): Adjust diagnostics for static or thread_local variables
+       in immediate functions.
+       (grokfndecl): Call sorry_at on virtual consteval.  Use %qs with keyword
+       to string to simplify translation.  Diagnose consteval main.  Use
+       SET_DECL_IMMEDIATE_FUNCTION_P for consteval.
+       (grokdeclarator): Handle consteval.  Use %qs with keyword strings to
+       simplify translation.  Use separate ifs instead of chained else if
+       for invalid specifiers.  For constinit clear constinit_p rather than
+       constexpr_p.
+       * constexpr.c (find_immediate_fndecl): New function.
+       (cxx_eval_outermost_constant_expr): Allow consteval calls returning
+       void.  Diagnose returning address of immediate function from consteval
+       evaluation.
+       (fold_non_dependent_expr_template): Add OBJECT argument, pass it
+       through to cxx_eval_outermost_constant_expr.
+       (fold_non_dependent_expr): Add OBJECT argument, pass it through to
+       fold_non_dependent_expr_template.
+       (fold_non_dependent_init): Adjust fold_non_dependent_expr_template
+       caller.
+       * method.c (defaulted_late_check): Adjust diagnostics for consteval.
+       * lambda.c (maybe_add_lambda_conv_op): Copy over
+       DECL_DECLARED_CONSTEXPR_P and DECL_IMMEDIATE_FUNCTION_P bits from
+       callop to both artificial functions.
+       * init.c (build_value_init): Don't do further processing if
+       build_special_member_call returned a TREE_CONSTANT.  Formatting fix.
+
        PR c++/91369 - Implement P0784R7: constexpr new
        * cp-tree.h (CALL_FROM_NEW_OR_DELETE_P): Define.
        * init.c (build_new_1, build_vec_delete_1, build_delete): Set
index b0c6370107ddf3a36f7ebcd765431db28ca41a45..3dac31a37b989e654b616a4ee3fdd2239dc7104c 100644 (file)
@@ -289,6 +289,9 @@ build_addr_func (tree function, tsubst_flags_t complain)
        }
       function = build_address (function);
     }
+  else if (TREE_CODE (function) == FUNCTION_DECL
+          && DECL_IMMEDIATE_FUNCTION_P (function))
+    function = build_address (function);
   else
     function = decay_conversion (function, complain, /*reject_builtin=*/false);
 
@@ -8145,6 +8148,40 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
                                   addr, nargs, argarray);
       if (TREE_THIS_VOLATILE (fn) && cfun)
        current_function_returns_abnormally = 1;
+      if (TREE_CODE (fn) == FUNCTION_DECL
+         && DECL_IMMEDIATE_FUNCTION_P (fn)
+         && (current_function_decl == NULL_TREE
+             || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
+         && (current_binding_level->kind != sk_function_parms
+             || !current_binding_level->immediate_fn_ctx_p))
+       {
+         tree obj_arg = NULL_TREE, exprimm = expr;
+         if (DECL_CONSTRUCTOR_P (fn))
+           obj_arg = first_arg;
+         if (obj_arg
+             && is_dummy_object (obj_arg)
+             && !type_dependent_expression_p (obj_arg))
+           {
+             exprimm = build_cplus_new (DECL_CONTEXT (fn), expr, complain);
+             obj_arg = NULL_TREE;
+           }
+         /* Look through *(const T *)&obj.  */
+         else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+           {
+             tree addr = TREE_OPERAND (obj_arg, 0);
+             STRIP_NOPS (addr);
+             if (TREE_CODE (addr) == ADDR_EXPR)
+               {
+                 tree typeo = TREE_TYPE (obj_arg);
+                 tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+                 if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+                   obj_arg = TREE_OPERAND (addr, 0);
+               }
+           }
+         fold_non_dependent_expr (exprimm, complain,
+                                  /*manifestly_const_eval=*/true,
+                                  obj_arg);
+       }
       return convert_from_reference (expr);
     }
 
@@ -8744,6 +8781,40 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
       if (TREE_CODE (c) == CALL_EXPR)
        TREE_NO_WARNING (c) = 1;
     }
+  if (TREE_CODE (fn) == ADDR_EXPR)
+    {
+      tree fndecl = STRIP_TEMPLATE (TREE_OPERAND (fn, 0));
+      if (TREE_CODE (fndecl) == FUNCTION_DECL
+         && DECL_IMMEDIATE_FUNCTION_P (fndecl)
+         && (current_function_decl == NULL_TREE
+             || !DECL_IMMEDIATE_FUNCTION_P (current_function_decl))
+         && (current_binding_level->kind != sk_function_parms
+             || !current_binding_level->immediate_fn_ctx_p))
+       {
+         tree obj_arg = NULL_TREE;
+         if (DECL_CONSTRUCTOR_P (fndecl))
+           obj_arg = cand->first_arg ? cand->first_arg : (*args)[0];
+         if (obj_arg && is_dummy_object (obj_arg))
+           {
+             call = build_cplus_new (DECL_CONTEXT (fndecl), call, complain);
+             obj_arg = NULL_TREE;
+           }
+         /* Look through *(const T *)&obj.  */
+         else if (obj_arg && TREE_CODE (obj_arg) == INDIRECT_REF)
+           {
+             tree addr = TREE_OPERAND (obj_arg, 0);
+             STRIP_NOPS (addr);
+             if (TREE_CODE (addr) == ADDR_EXPR)
+               {
+                 tree typeo = TREE_TYPE (obj_arg);
+                 tree typei = TREE_TYPE (TREE_OPERAND (addr, 0));
+                 if (same_type_ignoring_top_level_qualifiers_p (typeo, typei))
+                   obj_arg = TREE_OPERAND (addr, 0);
+               }
+           }
+         call = cxx_constant_value (call, obj_arg);
+       }
+    }
   return call;
 }
 
index 4baaac06252101053272dfbb7e49b9bd8bae6d00..84ed7accd7d4717231fdacbb1bfdbfe735166797 100644 (file)
@@ -5739,6 +5739,16 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void */*data*/)
   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
@@ -5767,13 +5777,38 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
 
   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))
     {
@@ -5874,6 +5909,25 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
          }
     }
 
+  /* 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.  */
@@ -6114,7 +6168,8 @@ clear_cv_and_fold_caches (bool sat /*= true*/)
 
 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);
 
@@ -6135,7 +6190,7 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
 
       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)
@@ -6171,16 +6226,17 @@ fold_non_dependent_expr_template (tree t, tsubst_flags_t complain,
 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);
 }
 
 
@@ -6197,7 +6253,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)
        {
index 6c9731f24db7f73f248e68a54a35441b2d7bc4ec..eb8563943773b20210e5285735fc66a44ae3c6d6 100644 (file)
@@ -2697,7 +2697,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.  */
 
@@ -3211,6 +3212,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.
@@ -5879,6 +5889,7 @@ enum cp_decl_spec {
   ds_constexpr,
   ds_complex,
   ds_constinit,
+  ds_consteval,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -7824,7 +7835,7 @@ extern tree maybe_constant_value          (tree, tree = NULL_TREE, bool = false);
 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);
index 72acc8f0224b3a96929bf0f6bdf6173754523c8f..8f22f230954aeef4d26ce3ff42aadfbd585543d2 100644 (file)
@@ -1225,7 +1225,13 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl)
     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 old_decl, tree new_decl)
          /* 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 old_decl, tree new_decl)
          && DECL_TEMPLATE_SPECIALIZATION (new_decl))
        return true;
 
+      const char *kind = "constexpr";
+      if (DECL_IMMEDIATE_FUNCTION_P (old_decl)
+         || DECL_IMMEDIATE_FUNCTION_P (new_decl))
+       kind = "consteval";
       error_at (DECL_SOURCE_LOCATION (new_decl),
-               "redeclaration %qD differs in %<constexpr%> "
-               "from previous declaration", new_decl);
+               "redeclaration %qD differs in %qs "
+               "from previous declaration", new_decl,
+               kind);
       inform (DECL_SOURCE_LOCATION (old_decl),
              "previous declaration %qD", old_decl);
       return false;
@@ -5024,12 +5037,15 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
       else if (saw_typedef)
        warning_at (declspecs->locations[ds_typedef], 0,
                    "%<typedef%> was ignored in this declaration");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constexpr))
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constexpr))
         error_at (declspecs->locations[ds_constexpr],
-                 "%<constexpr%> cannot be used for type declarations");
-      else if (decl_spec_seq_has_spec_p (declspecs,  ds_constinit))
+                 "%qs cannot be used for type declarations", "constexpr");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_constinit))
        error_at (declspecs->locations[ds_constinit],
-                 "%<constinit%> cannot be used for type declarations");
+                 "%qs cannot be used for type declarations", "constinit");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_consteval))
+       error_at (declspecs->locations[ds_consteval],
+                 "%qs cannot be used for type declarations", "consteval");
     }
 
   if (declspecs->attributes && warn_attributes && declared_type)
@@ -5387,11 +5403,14 @@ start_decl (const cp_declarator *declarator,
       bool ok = false;
       if (CP_DECL_THREAD_LOCAL_P (decl))
        error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD declared %<thread_local%> in %<constexpr%> function",
-                 decl);
+                 "%qD declared %<thread_local%> in %qs function", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
       else if (TREE_STATIC (decl))
        error_at (DECL_SOURCE_LOCATION (decl),
-                 "%qD declared %<static%> in %<constexpr%> function", decl);
+                 "%qD declared %<static%> in %qs function", decl,
+                 DECL_IMMEDIATE_FUNCTION_P (current_function_decl)
+                 ? "consteval" : "constexpr");
       else
        ok = true;
       if (!ok)
@@ -9342,6 +9361,15 @@ grokfndecl (tree ctype,
          }
     }
 
+  /* FIXME: For now.  */
+  if (virtualp && (inlinep & 8) != 0)
+    {
+      sorry_at (DECL_SOURCE_LOCATION (decl),
+               "%<virtual%> %<consteval%> method %qD not supported yet",
+               decl);
+      inlinep &= ~8;
+    }
+
   /* If this decl has namespace scope, set that up.  */
   if (in_namespace)
     set_decl_namespace (decl, in_namespace, friendp);
@@ -9389,7 +9417,10 @@ grokfndecl (tree ctype,
                  "cannot declare %<::main%> to be inline");
       if (inlinep & 2)
        error_at (declspecs->locations[ds_constexpr],
-                 "cannot declare %<::main%> to be %<constexpr%>");
+                 "cannot declare %<::main%> to be %qs", "constexpr");
+      if (inlinep & 8)
+       error_at (declspecs->locations[ds_consteval],
+                 "cannot declare %<::main%> to be %qs", "consteval");
       if (!publicp)
        error_at (location, "cannot declare %<::main%> to be static");
       inlinep = 0;
@@ -9428,6 +9459,11 @@ grokfndecl (tree ctype,
     }
   if (inlinep & 2)
     DECL_DECLARED_CONSTEXPR_P (decl) = true;
+  else if (inlinep & 8)
+    {
+      DECL_DECLARED_CONSTEXPR_P (decl) = true;
+      SET_DECL_IMMEDIATE_FUNCTION_P (decl);
+    }
 
   // If the concept declaration specifier was found, check
   // that the declaration satisfies the necessary requirements.
@@ -10786,6 +10822,7 @@ grokdeclarator (const cp_declarator *declarator,
   bool typedef_p = decl_spec_seq_has_spec_p (declspecs, ds_typedef);
   bool constexpr_p = decl_spec_seq_has_spec_p (declspecs, ds_constexpr);
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
+  bool consteval_p = decl_spec_seq_has_spec_p (declspecs, ds_consteval);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
   tree reqs = NULL_TREE;
@@ -11058,17 +11095,31 @@ grokdeclarator (const cp_declarator *declarator,
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
+  if (consteval_p && constexpr_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+               "both %qs and %qs specified", "constexpr", "consteval");
+      return error_mark_node;
+    }
+
   if (concept_p && typedef_p)
     {
       error_at (declspecs->locations[ds_concept],
-               "%<concept%> cannot appear in a typedef declaration");
+               "%qs cannot appear in a typedef declaration", "concept");
       return error_mark_node;
     }
 
   if (constexpr_p && typedef_p)
     {
       error_at (declspecs->locations[ds_constexpr],
-               "%<constexpr%> cannot appear in a typedef declaration");
+               "%qs cannot appear in a typedef declaration", "constexpr");
+      return error_mark_node;
+    }
+
+  if (consteval_p && typedef_p)
+    {
+      error_at (declspecs->locations[ds_consteval],
+               "%qs cannot appear in a typedef declaration", "consteval");
       return error_mark_node;
     }
 
@@ -11474,21 +11525,31 @@ grokdeclarator (const cp_declarator *declarator,
 
       /* Function parameters cannot be concept. */
       if (concept_p)
-       error_at (declspecs->locations[ds_concept],
-                 "a parameter cannot be declared %<concept%>");
+       {
+         error_at (declspecs->locations[ds_concept],
+                   "a parameter cannot be declared %qs", "concept");
+         concept_p = 0;
+         constexpr_p = 0;
+       }
       /* Function parameters cannot be constexpr.  If we saw one, moan
          and pretend it wasn't there.  */
       else if (constexpr_p)
         {
           error_at (declspecs->locations[ds_constexpr],
-                   "a parameter cannot be declared %<constexpr%>");
+                   "a parameter cannot be declared %qs", "constexpr");
           constexpr_p = 0;
         }
-      else if (constinit_p)
+      if (constinit_p)
        {
          error_at (declspecs->locations[ds_constinit],
-                   "a parameter cannot be declared %<constinit%>");
-         constexpr_p = 0;
+                   "a parameter cannot be declared %qs", "constinit");
+         constinit_p = 0;
+       }
+      if (consteval_p)
+       {
+         error_at (declspecs->locations[ds_consteval],
+                   "a parameter cannot be declared %qs", "consteval");
+         consteval_p = 0;
        }
     }
 
@@ -11511,9 +11572,12 @@ grokdeclarator (const cp_declarator *declarator,
       if (typedef_p)
        error_at (declspecs->locations[ds_typedef],
                  "structured binding declaration cannot be %qs", "typedef");
-      if (constexpr_p)
+      if (constexpr_p && !concept_p)
        error_at (declspecs->locations[ds_constexpr], "structured "
                  "binding declaration cannot be %qs", "constexpr");
+      if (consteval_p)
+       error_at (declspecs->locations[ds_consteval], "structured "
+                 "binding declaration cannot be %qs", "consteval");
       if (thread_p && cxx_dialect < cxx2a)
        pedwarn (declspecs->locations[ds_thread], 0,
                 "structured binding declaration can be %qs only in "
@@ -11573,6 +11637,7 @@ grokdeclarator (const cp_declarator *declarator,
       inlinep = 0;
       typedef_p = 0;
       constexpr_p = 0;
+      consteval_p = 0;
       concept_p = 0;
       if (storage_class != sc_static)
        {
@@ -12967,7 +13032,7 @@ grokdeclarator (const cp_declarator *declarator,
                 if (concept_p)
                   {
                     error_at (declspecs->locations[ds_concept],
-                             "a destructor cannot be %<concept%>");
+                             "a destructor cannot be %qs", "concept");
                     return error_mark_node;
                   }
                if (constexpr_p && cxx_dialect < cxx2a)
@@ -12977,6 +13042,12 @@ grokdeclarator (const cp_declarator *declarator,
                              " with %<-std=c++2a%> or %<-std=gnu++2a%>");
                    return error_mark_node;
                  }
+               if (consteval_p)
+                 {
+                   error_at (declspecs->locations[ds_consteval],
+                             "a destructor cannot be %qs", "consteval");
+                   return error_mark_node;
+                 }
              }
            else if (sfk == sfk_constructor && friendp && !ctype)
              {
@@ -12998,6 +13069,14 @@ grokdeclarator (const cp_declarator *declarator,
                          "a concept cannot be a member function");
                concept_p = false;
              }
+           else if (consteval_p
+                    && identifier_p (unqualified_id)
+                    && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+             {
+               error_at (declspecs->locations[ds_consteval],
+                         "%qD cannot be %qs", unqualified_id, "consteval");
+               consteval_p = false;
+             }
 
            if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
              {
@@ -13028,7 +13107,8 @@ grokdeclarator (const cp_declarator *declarator,
                               reqs,
                               virtualp, flags, memfn_quals, rqual, raises,
                               friendp ? -1 : 0, friendp, publicp,
-                               inlinep | (2 * constexpr_p) | (4 * concept_p),
+                              inlinep | (2 * constexpr_p) | (4 * concept_p)
+                                      | (8 * consteval_p),
                               initialized == SD_DELETED, sfk,
                               funcdef_flag, late_return_type_p,
                               template_count, in_namespace,
@@ -13130,8 +13210,8 @@ grokdeclarator (const cp_declarator *declarator,
                set_linkage_for_static_data_member (decl);
                if (concept_p)
                  error_at (declspecs->locations[ds_concept],
-                           "static data member %qE declared %<concept%>",
-                           unqualified_id);
+                           "static data member %qE declared %qs",
+                           unqualified_id, "concept");
                else if (constexpr_p && !initialized)
                  {
                    error_at (DECL_SOURCE_LOCATION (decl),
@@ -13139,6 +13219,10 @@ grokdeclarator (const cp_declarator *declarator,
                              "have an initializer", decl);
                    constexpr_p = false;
                  }
+               if (consteval_p)
+                 error_at (declspecs->locations[ds_consteval],
+                           "static data member %qE declared %qs",
+                           unqualified_id, "consteval");
 
                if (inlinep)
                  mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -13163,23 +13247,34 @@ grokdeclarator (const cp_declarator *declarator,
            else
              {
                if (concept_p)
-                 error_at (declspecs->locations[ds_concept],
-                           "non-static data member %qE declared %<concept%>",
-                           unqualified_id);
-                else if (constexpr_p)
+                 {
+                   error_at (declspecs->locations[ds_concept],
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "concept");
+                   concept_p = false;
+                   constexpr_p = false;
+                 }
+               else if (constexpr_p)
                  {
                    error_at (declspecs->locations[ds_constexpr],
-                             "non-static data member %qE declared "
-                             "%<constexpr%>", unqualified_id);
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "constexpr");
                    constexpr_p = false;
                  }
-               else if (constinit_p)
+               if (constinit_p)
                  {
                    error_at (declspecs->locations[ds_constinit],
-                             "non-static data member %qE declared "
-                             "%<constinit%>", unqualified_id);
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "constinit");
                    constinit_p = false;
                  }
+               if (consteval_p)
+                 {
+                   error_at (declspecs->locations[ds_consteval],
+                             "non-static data member %qE declared %qs",
+                             unqualified_id, "consteval");
+                   consteval_p = false;
+                 }
                decl = build_decl (id_loc, FIELD_DECL, unqualified_id, type);
                DECL_NONADDRESSABLE_P (decl) = bitfield;
                if (bitfield && !unqualified_id)
@@ -13285,6 +13380,14 @@ grokdeclarator (const cp_declarator *declarator,
                sfk = sfk_none;
              }
          }
+       if (consteval_p
+           && identifier_p (unqualified_id)
+           && IDENTIFIER_NEWDEL_OP_P (unqualified_id))
+         {
+           error_at (declspecs->locations[ds_consteval],
+                     "%qD cannot be %qs", unqualified_id, "consteval");
+           consteval_p = false;
+         }
 
        /* Record whether the function is public.  */
        publicp = (ctype != NULL_TREE
@@ -13295,7 +13398,8 @@ grokdeclarator (const cp_declarator *declarator,
                            reqs, virtualp, flags, memfn_quals, rqual, raises,
                           1, friendp,
                           publicp,
-                           inlinep | (2 * constexpr_p) | (4 * concept_p),
+                          inlinep | (2 * constexpr_p) | (4 * concept_p)
+                                  | (8 * consteval_p),
                           initialized == SD_DELETED,
                            sfk,
                            funcdef_flag,
@@ -13388,6 +13492,12 @@ grokdeclarator (const cp_declarator *declarator,
                      "is not a definition", decl);
            constexpr_p = false;
          }
+       if (consteval_p)
+         {
+           error_at (DECL_SOURCE_LOCATION (decl),
+                     "a variable cannot be declared %<consteval%>");
+           consteval_p = false;
+         }
 
        if (inlinep)
          mark_inline_variable (decl, declspecs->locations[ds_inline]);
@@ -16696,7 +16806,7 @@ finish_function (bool inline_p)
     invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
 
   /* Perform delayed folding before NRV transformation.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_fold_function (fndecl);
 
   /* Set up the named return value optimization, if we can.  Candidate
@@ -16813,7 +16923,7 @@ finish_function (bool inline_p)
     do_warn_unused_parameter (fndecl);
 
   /* Genericize before inlining.  */
-  if (!processing_template_decl)
+  if (!processing_template_decl && !DECL_IMMEDIATE_FUNCTION_P (fndecl))
     cp_genericize (fndecl);
 
   /* We're leaving the context of this function, so zap cfun.  It's still in
index 83b8b12e4bdb19975cc5fba6eb2a6d08416668d8..d104a4d574c40e5ff04b0be3e898970900536b4d 100644 (file)
@@ -1652,7 +1652,9 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
         {
           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");
        }
     }
index f86cf55103976c626157364775aaf6e694efe8ad..eda827250dab82fa9d0b6ba11a2f42f0f3198f99 100644 (file)
@@ -348,14 +348,12 @@ build_value_init (tree type, tsubst_flags_t complain)
   gcc_assert (!processing_template_decl
              || (SCALAR_TYPE_P (type) || TREE_CODE (type) == ARRAY_TYPE));
 
-  if (CLASS_TYPE_P (type)
-      && type_build_ctor_call (type))
+  if (CLASS_TYPE_P (type) && type_build_ctor_call (type))
     {
-      tree ctor =
-        build_special_member_call (NULL_TREE, complete_ctor_identifier,
-                                   NULL, type, LOOKUP_NORMAL,
-                                   complain);
-      if (ctor == error_mark_node)
+      tree ctor
+       = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                    NULL, type, LOOKUP_NORMAL, complain);
+      if (ctor == error_mark_node || TREE_CONSTANT (ctor))
        return ctor;
       tree fn = NULL_TREE;
       if (TREE_CODE (ctor) == CALL_EXPR)
index d621beca2ebb2817270c971f9d25f0ced71af03d..c582aa5b10573f9e7a6b9ac696f4d2c4193bda31 100644 (file)
@@ -1194,6 +1194,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_ARTIFICIAL (fn) = 1;
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = build_this_parm (fn, fntype, TYPE_QUAL_CONST);
 
   if (nested_def)
@@ -1226,6 +1229,9 @@ maybe_add_lambda_conv_op (tree type)
   DECL_NOT_REALLY_EXTERN (fn) = 1;
   DECL_DECLARED_INLINE_P (fn) = 1;
   DECL_STATIC_FUNCTION_P (fn) = 1;
+  DECL_DECLARED_CONSTEXPR_P (fn) = DECL_DECLARED_CONSTEXPR_P (callop);
+  if (DECL_IMMEDIATE_FUNCTION_P (callop))
+    SET_DECL_IMMEDIATE_FUNCTION_P (fn);
   DECL_ARGUMENTS (fn) = fn_args;
   for (tree arg = fn_args; arg; arg = DECL_CHAIN (arg))
     {
index b613e5df871bb79ec5ce9badf366d261dff1156a..09e9c73cda59c7cb03cc6c6b1640a6168473dd9a 100644 (file)
@@ -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;
index b44687e96bb6653fe421226fc108b131e456ca90..0b7bf83c4f436722eaa1007356984c1b2069b151 100644 (file)
@@ -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.  */
index f1664e66087fce28a21def7c0b45feb54109f01e..516c14b5610decd7b9c27d73ebc1a885a0c4f519 100644 (file)
@@ -998,11 +998,13 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* GNU extensions.  */
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
-      /* C++0x extensions.  */
+      /* C++11 extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
     case RID_CONSTEXPR:
+      /* C++20 extensions.  */
     case RID_CONSTINIT:
+    case RID_CONSTEVAL:
       return true;
 
     default:
@@ -1807,12 +1809,15 @@ enum
   /* When parsing a decl-specifier-seq, only allow type-specifier or
      constexpr.  */
   CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8,
-  /* When parsing a decl-specifier-seq, only allow mutable or constexpr.  */
+  /* When parsing a decl-specifier-seq, only allow mutable, constexpr or
+     for C++2A consteval.  */
   CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR = 0x10,
   /* When parsing a decl-specifier-seq, allow missing typename.  */
   CP_PARSER_FLAGS_TYPENAME_OPTIONAL = 0x20,
   /* When parsing of the noexcept-specifier should be delayed.  */
-  CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40
+  CP_PARSER_FLAGS_DELAY_NOEXCEPT = 0x40,
+  /* When parsing a consteval declarator.  */
+  CP_PARSER_FLAGS_CONSTEVAL = 0x80
 };
 
 /* This type is used for parameters and variables which hold
@@ -2671,6 +2676,7 @@ static bool cp_parser_init_statement_p
   (cp_parser *);
 static bool cp_parser_skip_to_closing_square_bracket
   (cp_parser *);
+static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t);
 
 // -------------------------------------------------------------------------- //
 // Unevaluated Operand Guard
@@ -10903,11 +10909,31 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
      opening parenthesis if present.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
     {
+      bool is_consteval = false;
+      /* For C++20, before parsing the parameter list check if there is
+        a consteval specifier in the corresponding decl-specifier-seq.  */
+      if (cxx_dialect >= cxx2a)
+       {
+         for (size_t n = cp_parser_skip_balanced_tokens (parser, 1);
+              cp_lexer_nth_token_is (parser->lexer, n, CPP_KEYWORD); n++)
+           {
+             if (cp_lexer_peek_nth_token (parser->lexer, n)->keyword
+                 == RID_CONSTEVAL)
+               {
+                 is_consteval = true;
+                 break;
+               }
+           }
+       }
+
       matching_parens parens;
       parens.consume_open (parser);
 
       begin_scope (sk_function_parms, /*entity=*/NULL_TREE);
 
+      if (is_consteval)
+       current_binding_level->immediate_fn_ctx_p = true;
+
       /* Parse parameters.  */
       param_list
        = cp_parser_parameter_declaration_clause
@@ -10992,6 +11018,9 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
                    "lambda only available with %<-std=c++17%> or "
                    "%<-std=gnu++17%>");
       }
+    if (lambda_specs.locations[ds_consteval])
+      return_type_specs.locations[ds_consteval]
+       = lambda_specs.locations[ds_consteval];
 
     p = obstack_alloc (&declarator_obstack, 0);
 
@@ -14052,6 +14081,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          cp_lexer_consume_token (parser->lexer);
          break;
 
+       case RID_CONSTEVAL:
+         ds = ds_consteval;
+         cp_lexer_consume_token (parser->lexer);
+         break;
+
         case RID_CONCEPT:
           ds = ds_concept;
           cp_lexer_consume_token (parser->lexer);
@@ -14169,7 +14203,8 @@ cp_parser_decl_specifier_seq (cp_parser* 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 +17345,10 @@ cp_parser_explicit_instantiation (cp_parser* parser)
            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 +20334,9 @@ cp_parser_init_declarator (cp_parser* parser,
   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 +20981,10 @@ cp_parser_direct_declarator (cp_parser* 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 +30006,10 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
            "friend",
            "typedef",
            "using",
-            "constexpr",
+           "constexpr",
            "__complex",
-           "constinit"
+           "constinit",
+           "consteval"
          };
          gcc_rich_location richloc (location);
          richloc.add_fixit_remove ();
index 59def3170ab11d46a565ba1e6e7d5ccf0c498e6c..8293c0721bd5d295de894bfc43e62c962bbfe057 100644 (file)
@@ -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)))))
index 03c39b3e3b92d434074d935c1aa8c017f0748d72..15529c66b1efa62b2021b7b459e0082ce7b927dc 100644 (file)
@@ -6176,6 +6176,16 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
   if (processing_template_decl || TREE_CODE (arg) != COMPONENT_REF)
     {
       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;
index c5293582e9a92ebe92649a9b43e854f4a7d3d2ef..5473b252e731a7ab9136fed99ae039512563f848 100644 (file)
@@ -1,5 +1,22 @@
 2019-11-02  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c++/88335 - Implement P1073R3: Immediate functions
+       * g++.dg/cpp2a/consteval1.C: New test.
+       * g++.dg/cpp2a/consteval2.C: New test.
+       * g++.dg/cpp2a/consteval3.C: New test.
+       * g++.dg/cpp2a/consteval4.C: New test.
+       * g++.dg/cpp2a/consteval5.C: New test.
+       * g++.dg/cpp2a/consteval6.C: New test.
+       * g++.dg/cpp2a/consteval7.C: New test.
+       * g++.dg/cpp2a/consteval8.C: New test.
+       * g++.dg/cpp2a/consteval9.C: New test.
+       * g++.dg/cpp2a/consteval10.C: New test.
+       * g++.dg/cpp2a/consteval11.C: New test.
+       * g++.dg/cpp2a/consteval12.C: New test.
+       * g++.dg/cpp2a/consteval13.C: New test.
+       * g++.dg/cpp2a/consteval14.C: New test.
+       * g++.dg/ext/consteval1.C: New test.
+
        PR c++/91369 - Implement P0784R7: constexpr new
        * g++.dg/cpp2a/constexpr-new6.C: New test.
        * g++.dg/cpp2a/constexpr-new7.C: New test.
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval1.C b/gcc/testsuite/g++.dg/cpp2a/consteval1.C
new file mode 100644 (file)
index 0000000..fa00b07
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval10.C b/gcc/testsuite/g++.dg/cpp2a/consteval10.C
new file mode 100644 (file)
index 0000000..6785f60
--- /dev/null
@@ -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 } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval11.C b/gcc/testsuite/g++.dg/cpp2a/consteval11.C
new file mode 100644 (file)
index 0000000..2f68ec0
--- /dev/null
@@ -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> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval12.C b/gcc/testsuite/g++.dg/cpp2a/consteval12.C
new file mode 100644 (file)
index 0000000..0e97cf2
--- /dev/null
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+   auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+   constexpr auto e = qux ();
+   static_assert (e == 42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval13.C b/gcc/testsuite/g++.dg/cpp2a/consteval13.C
new file mode 100644 (file)
index 0000000..8db7e66
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+consteval int bar () { return 42; }
+consteval int baz () { return 1; }
+typedef int (*fnptr) ();
+consteval fnptr quux () { return bar; }
+
+void
+foo ()
+{
+   auto qux = [] (fnptr a = quux ()) consteval { return a (); };
+   constexpr auto c = qux (baz);       // { dg-error "taking address of an immediate function" }
+   constexpr auto d = qux (bar);       // { dg-error "taking address of an immediate function" }
+   static_assert (c == 1);
+   static_assert (d == 42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval14.C b/gcc/testsuite/g++.dg/cpp2a/consteval14.C
new file mode 100644 (file)
index 0000000..54ab927
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+
+template <int N>
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  S b = 12;
+  c.a += b.a;
+  c.b += b.b;
+  S e[2];
+  S f[2] = { 1, 2 };
+  const S g;
+  c.a += g.a;
+  c.b += g.b;
+  const S h = 12;
+  c.a += h.a;
+  c.b += h.b;
+  const S i[2];
+  const S j[2] = { 1, 2 };
+  return S ().a + e[1].a + f[0].b + i[0].a + j[1].b;
+}
+
+int x = foo <2> ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval2.C b/gcc/testsuite/g++.dg/cpp2a/consteval2.C
new file mode 100644 (file)
index 0000000..8975002
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval3.C b/gcc/testsuite/g++.dg/cpp2a/consteval3.C
new file mode 100644 (file)
index 0000000..4214092
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval4.C b/gcc/testsuite/g++.dg/cpp2a/consteval4.C
new file mode 100644 (file)
index 0000000..3e55c2b
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval5.C b/gcc/testsuite/g++.dg/cpp2a/consteval5.C
new file mode 100644 (file)
index 0000000..600ce40
--- /dev/null
@@ -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 ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval6.C b/gcc/testsuite/g++.dg/cpp2a/consteval6.C
new file mode 100644 (file)
index 0000000..72d5f79
--- /dev/null
@@ -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" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval7.C b/gcc/testsuite/g++.dg/cpp2a/consteval7.C
new file mode 100644 (file)
index 0000000..10e4ea4
--- /dev/null
@@ -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 ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval8.C b/gcc/testsuite/g++.dg/cpp2a/consteval8.C
new file mode 100644 (file)
index 0000000..105737d
--- /dev/null
@@ -0,0 +1,29 @@
+// { dg-do compile }
+// { dg-options "-std=c++2a" }
+
+struct S { consteval S () : a (1), b (2) { a++; b++; } consteval S (int x) : a (x), b (x) { a++; b--; } int a, b; };
+S c;
+S d = 25;
+
+int
+foo ()
+{
+  S a;
+  a.b++;
+  c = a;
+  S b = 12;
+  c.a += b.a;
+  c.b += b.b;
+  S e[2];
+  S f[2] = { 1, 2 };
+  return S ().a + e[1].a + f[0].b;
+}
+
+constexpr S g;
+constexpr S h = 42;
+constexpr S i[2];
+constexpr S j[2] = { 3, 4 };
+static_assert (g.a == 2 && g.b == 3);
+static_assert (h.a == 43 && h.b == 41);
+static_assert (i[0].a == 2 && i[0].b == 3 && i[1].a == 2 && i[1].b == 3);
+static_assert (j[0].a == 4 && j[0].b == 2 && j[1].a == 5 && j[1].b == 3);
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval9.C b/gcc/testsuite/g++.dg/cpp2a/consteval9.C
new file mode 100644 (file)
index 0000000..489286a
--- /dev/null
@@ -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\\)'" }
diff --git a/gcc/testsuite/g++.dg/ext/consteval1.C b/gcc/testsuite/g++.dg/ext/consteval1.C
new file mode 100644 (file)
index 0000000..928e0f8
--- /dev/null
@@ -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" }