On 10/4/19 1:50 PM, Jakub Jelinek wrote:
On Thu, Oct 03, 2019 at 04:07:14PM -0400, Jason Merrill wrote:
I believe it doesn't, because the heap VAR_DECLs are TREE_STATIC (things
really don't work at all if they aren't).

Ah, sure.  I suppose you could clear TREE_STATIC from them before the
verify_constant in this function?

That works, but generates uglier diagnostics.
Otherwise, I've tried to address all your comments.

So, here is the updated patch without the find_heap_var_refs removal and
TREE_STATIC clearing (tested so far just with
make check-c++-all RUNTESTFLAGS="--target_board=unix\{-m32,-m64\} 
dg.exp='constexpr-array* eval-order* is_literal* constexpr-new* constexpr-dtor* 
constexpr-delete* locations1.C feat-cxx*'
) plus attached incremental patch for the find_heap_var_refs removal and
TREE_STATIC clearing.  The difference can be seen in the incremental diff,
the ugly part is
error: '(int*)(& heap deleted)' is not a constant expression
but it will show up only if the constant to be verified contains pointers to
deallocated heap, if it still contains pointers to allocated heap, it will
instead complain about allocated heap not being deallocated.

2019-10-04  Jakub Jelinek  <ja...@redhat.com>

        PR c++/91369 - Implement P0784R7: constexpr new
c-family/
        * c-cppbuiltin.c (c_cpp_builtins): Predefine
        __cpp_constexpr_dynamic_alloc=201907 for -std=c++2a.
cp/
        * cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_UNINIT_IDENTIFIER,
        CPTI_HEAP_IDENTIFIER and CPTI_HEAP_DELETED_IDENTIFIER.
        (heap_uninit_identifier, heap_identifier, heap_deleted_identifier):
        Define.
        (type_has_constexpr_destructor, build_new_constexpr_heap_type,
        cxx_constant_dtor): Declare.
        * class.c (type_maybe_constexpr_default_constructor): Make static.
        (type_maybe_constexpr_destructor, type_has_constexpr_destructor): New
        functions.
        (finalize_literal_type_property): For c++2a, don't clear
        CLASSTYPE_LITERAL_P for types without trivial destructors unless they
        have non-constexpr destructors.
        (explain_non_literal_class): For c++2a, complain about non-constexpr
        destructors rather than about non-trivial destructors.
        * constexpr.c: Include stor-layout.h.
        (struct constexpr_global_ctx): New type.
        (struct constexpr_ctx): Add global field, remove values and
        constexpr_ops_count.
        (cxx_eval_call_expression): For c++2a allow calls to replaceable
        global allocation functions, for new return address of a heap uninit
        var, for delete record its deletion.  Change ctx->values->{get,put} to
        ctx->global->values.{get,put}.
        (non_const_var_error): Add auto_diagnostic_group sentinel.  Emit
        special diagnostics for heap variables.
        (cxx_eval_store_expression): Change ctx->values->{get,put} to
        ctx->global->values.{get,put}.
        (cxx_eval_loop_expr): Initialize jump_target if NULL.  Change
        new_ctx.values->remove to ctx->global->values.remove.
        (cxx_eval_constant_expression): Change *ctx->constexpr_ops_count
        to ctx->global->constexpr_ops_count.  Change ctx->values->{get,put} to
        ctx->global->values.{get,put}.
        <case NOP_EXPR>: Formatting fix.  On cast of replaceable global
        allocation function to some pointer type, adjust the type of
        the heap variable and change name from heap_uninit_identifier
        to heap_identifier.
        (find_heap_var_refs): New function.
        (cxx_eval_outermost_constant_expr): Add constexpr_dtor argument,
        handle evaluation of constexpr dtors and add tracking of heap
        variables.  Use tf_no_cleanup for get_target_expr_with_sfinae.
        (cxx_constant_value): Adjust cxx_eval_outermost_constant_expr caller.
        (cxx_constant_dtor): New function.
        (maybe_constant_value, fold_non_dependent_expr_template,
        maybe_constant_init_1): Adjust cxx_eval_outermost_constant_expr
        callers.
        (potential_constant_expression_1): Ignore clobbers.  Allow
        COND_EXPR_IS_VEC_DELETE for c++2a.
        * decl.c (initialize_predefined_identifiers): Add heap identifiers.
        (decl_maybe_constant_destruction): New function.
        (cp_finish_decl): Don't clear TREE_READONLY for constexpr variables
        with non-trivial, but constexpr destructors.
        (register_dtor_fn): For constexpr variables with constexpr non-trivial
        destructors call cxx_maybe_build_cleanup instead of adding destructor
        calls at runtime.
        (expand_static_init): For constexpr variables with constexpr
        non-trivial destructors call cxx_maybe_build_cleanup.
        (grokdeclarator): Allow constexpr destructors for c++2a.  Formatting
        fix.
        (cxx_maybe_build_cleanup): For constexpr variables with constexpr
        non-trivial destructors call cxx_constant_dtor instead of adding
        destructor calls at runtime.
        * init.c: Include stor-layout.h.
        (build_new_constexpr_heap_type, maybe_wrap_new_for_constexpr): New
        functions.
        (build_new_1): For c++2a and new[], add cast around the alloc call
        to help constexpr evaluation figure out the type of the heap storage.
        (build_vec_delete_1): Set DECL_INITIAL of tbase and emit a DECL_EXPR
        for it instead of initializing an uninitialized variable.
        * method.c: Include intl.h.
        (SFK_CTOR_P, SFK_DTOR_P, SFK_ASSIGN_P, SFK_COPY_P, SFK_MOVE_P): Move
        definitions earlier.
        (process_subob_fn): Add sfk argument, adjust non-constexpr call
        diagnostics based on it.
        (walk_field_subobs): Formatting fixes.  Adjust process_subob_fn caller.
        (synthesized_method_base_walk): Likewise.
        (synthesized_method_walk): Set *constexpr_p to true for dtors in c++2a.
        Fix up DR number in comment.
        (implicitly_declare_fn): Formatting fix.
        * typeck2.c (store_init_value): Don't call cp_fully_fold_init on
        initializers of automatic non-constexpr variables in constexpr
        functions.
testsuite/
        * g++.dg/cpp0x/constexpr-delete2.C: Adjust expected diagnostics for
        c++2a.
        * g++.dg/cpp0x/locations1.C: Only expect constexpr ~S() diagnostics
        in c++17_down, adjust expected wording.
        * g++.dg/cpp1y/constexpr-new.C: Only expect diagnostics in c++17_down.
        * g++.dg/cpp2a/constexpr-dtor1.C: New test.
        * g++.dg/cpp2a/constexpr-dtor2.C: New test.
        * g++.dg/cpp2a/constexpr-dtor3.C: New test.
        * g++.dg/cpp2a/constexpr-new1.C: New test.
        * g++.dg/cpp2a/constexpr-new2.C: New test.
        * g++.dg/cpp2a/constexpr-new3.C: New test.
        * g++.dg/cpp2a/constexpr-new4.C: New test.
        * g++.dg/cpp2a/feat-cxx2a.C: Add __cpp_constinit and
        __cpp_constexpr_dynamic_alloc tests.  Tweak __cpp_* tests for c++2a
        features to use style like older features, including #ifdef test.
        * g++.dg/ext/is_literal_type3.C: New test.

--- gcc/c-family/c-cppbuiltin.c.jj      2019-10-03 17:55:28.657054188 +0200
+++ gcc/c-family/c-cppbuiltin.c 2019-10-04 12:49:21.610028880 +0200
@@ -989,6 +989,7 @@ c_cpp_builtins (cpp_reader *pfile)
          cpp_define (pfile, "__cpp_constinit=201907");
          cpp_define (pfile, "__cpp_nontype_template_parameter_class=201806");
          cpp_define (pfile, "__cpp_impl_destroying_delete=201806");
+         cpp_define (pfile, "__cpp_constexpr_dynamic_alloc=201907");
        }
        if (flag_concepts)
        cpp_define (pfile, "__cpp_concepts=201507");
--- gcc/cp/cp-tree.h.jj 2019-10-03 17:55:28.526056167 +0200
+++ gcc/cp/cp-tree.h    2019-10-04 18:51:24.935599025 +0200
@@ -172,6 +172,9 @@ enum cp_tree_index
      CPTI_VALUE_IDENTIFIER,
      CPTI_FUN_IDENTIFIER,
      CPTI_CLOSURE_IDENTIFIER,
+    CPTI_HEAP_UNINIT_IDENTIFIER,
+    CPTI_HEAP_IDENTIFIER,
+    CPTI_HEAP_DELETED_IDENTIFIER,
CPTI_LANG_NAME_C,
      CPTI_LANG_NAME_CPLUSPLUS,
@@ -310,6 +313,9 @@ extern GTY(()) tree cp_global_trees[CPTI
  #define value_identifier              cp_global_trees[CPTI_VALUE_IDENTIFIER]
  #define fun_identifier                        
cp_global_trees[CPTI_FUN_IDENTIFIER]
  #define closure_identifier            cp_global_trees[CPTI_CLOSURE_IDENTIFIER]
+#define heap_uninit_identifier         
cp_global_trees[CPTI_HEAP_UNINIT_IDENTIFIER]
+#define heap_identifier                        
cp_global_trees[CPTI_HEAP_IDENTIFIER]
+#define heap_deleted_identifier                
cp_global_trees[CPTI_HEAP_DELETED_IDENTIFIER]
  #define lang_name_c                   cp_global_trees[CPTI_LANG_NAME_C]
  #define lang_name_cplusplus           
cp_global_trees[CPTI_LANG_NAME_CPLUSPLUS]
@@ -6342,6 +6348,7 @@ extern bool vbase_has_user_provided_move
  extern tree default_init_uninitialized_part (tree);
  extern bool trivial_default_constructor_is_constexpr (tree);
  extern bool type_has_constexpr_default_constructor (tree);
+extern bool type_has_constexpr_destructor      (tree);
  extern bool type_has_virtual_destructor               (tree);
  extern bool classtype_has_move_assign_or_move_ctor_p (tree, bool 
user_declared);
  extern bool classtype_has_non_deleted_move_ctor (tree);
@@ -6648,6 +6655,7 @@ extern tree build_offset_ref                      (tree, 
tr
  extern tree throw_bad_array_new_length                (void);
  extern bool type_has_new_extended_alignment   (tree);
  extern unsigned malloc_alignment              (void);
+extern tree build_new_constexpr_heap_type      (tree, tree, tree);
  extern tree build_new                         (vec<tree, va_gc> **, tree, 
tree,
                                                 vec<tree, va_gc> **, int,
                                                   tsubst_flags_t);
@@ -7747,6 +7755,7 @@ extern bool require_constant_expression
  extern bool require_rvalue_constant_expression (tree);
  extern bool require_potential_rvalue_constant_expression (tree);
  extern tree cxx_constant_value                        (tree, tree = 
NULL_TREE);
+extern void cxx_constant_dtor                  (tree, tree);
  extern tree cxx_constant_init                 (tree, tree = NULL_TREE);
  extern tree maybe_constant_value              (tree, tree = NULL_TREE, bool = 
false);
  extern tree maybe_constant_init                       (tree, tree = 
NULL_TREE, bool = false);
--- gcc/cp/class.c.jj   2019-10-03 17:55:28.554055744 +0200
+++ gcc/cp/class.c      2019-10-04 12:49:21.336033076 +0200
@@ -206,6 +206,7 @@ static int empty_base_at_nonzero_offset_
  static tree end_of_base (tree);
  static tree get_vcall_index (tree, tree);
  static bool type_maybe_constexpr_default_constructor (tree);
+static bool type_maybe_constexpr_destructor (tree);
  static bool field_poverlapping_p (tree);
/* Return a COND_EXPR that executes TRUE_STMT if this execution of the
@@ -5242,7 +5243,7 @@ type_has_constexpr_default_constructor (
     without forcing a lazy declaration (which might cause undesired
     instantiations).  */
-bool
+static bool
  type_maybe_constexpr_default_constructor (tree t)
  {
    if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DEFAULT_CTOR (t)
@@ -5252,6 +5253,34 @@ type_maybe_constexpr_default_constructor
    return type_has_constexpr_default_constructor (t);
  }
+/* Returns true iff class T has a constexpr destructor. */
+
+bool
+type_has_constexpr_destructor (tree t)
+{
+  tree fns;
+
+  if (CLASSTYPE_LAZY_DESTRUCTOR (t))
+    /* Non-trivial, we need to check subobject destructors.  */
+    lazily_declare_fn (sfk_destructor, t);
+  fns = CLASSTYPE_DESTRUCTOR (t);
+  return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
+}
+
+/* Returns true iff class T has a constexpr destructor or has an
+   implicitly declared destructor that we can't tell if it's constexpr
+   without forcing a lazy declaration (which might cause undesired
+   instantiations).  */
+
+static bool
+type_maybe_constexpr_destructor (tree t)
+{
+  if (CLASS_TYPE_P (t) && CLASSTYPE_LAZY_DESTRUCTOR (t))
+    /* Assume it's constexpr.  */
+    return true;
+  return type_has_constexpr_destructor (t);
+}
+
  /* Returns true iff class TYPE has a virtual destructor.  */
bool
@@ -5503,8 +5532,11 @@ finalize_literal_type_property (tree t)
  {
    tree fn;
- if (cxx_dialect < cxx11
-      || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+  if (cxx_dialect < cxx11)
+    CLASSTYPE_LITERAL_P (t) = false;
+  else if (CLASSTYPE_LITERAL_P (t)
+          && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+          && (cxx_dialect < cxx2a || !type_maybe_constexpr_destructor (t)))
      CLASSTYPE_LITERAL_P (t) = false;
    else if (CLASSTYPE_LITERAL_P (t) && LAMBDA_TYPE_P (t))
      CLASSTYPE_LITERAL_P (t) = (cxx_dialect >= cxx17);
@@ -5558,8 +5590,12 @@ explain_non_literal_class (tree t)
      inform (UNKNOWN_LOCATION,
            "  %qT is a closure type, which is only literal in "
            "C++17 and later", t);
-  else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
+  else if (cxx_dialect < cxx2a && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t))
      inform (UNKNOWN_LOCATION, "  %q+T has a non-trivial destructor", t);
+  else if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t)
+          && !type_maybe_constexpr_destructor (t))
+    inform (UNKNOWN_LOCATION, "  %q+T does not have %<constexpr%> destructor",
+           t);
    else if (CLASSTYPE_NON_AGGREGATE (t)
           && !TYPE_HAS_TRIVIAL_DFLT (t)
           && !LAMBDA_TYPE_P (t)
--- gcc/cp/constexpr.c.jj       2019-10-04 08:54:52.902007011 +0200
+++ gcc/cp/constexpr.c  2019-10-04 19:17:43.984309712 +0200
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.
  #include "gimple-fold.h"
  #include "timevar.h"
  #include "fold-const-call.h"
+#include "stor-layout.h"
static bool verify_constant (tree, bool, bool *, bool *);
  #define VERIFY_CONSTANT(X)                                            \
@@ -1006,17 +1007,35 @@ enum constexpr_switch_state {
    css_default_processing
  };
+/* The constexpr expansion context part which needs one instance per
+   cxx_eval_outermost_constant_expr invocation.  VALUES is a map of values of
+   variables initialized within the expression.  */
+
+struct constexpr_global_ctx {
+  /* Values for any temporaries or local variables within the
+     constant-expression. */
+  hash_map<tree,tree> values;
+  /* Number of cxx_eval_constant_expression calls (except skipped ones,
+     on simple constants or location wrappers) encountered during current
+     cxx_eval_outermost_constant_expr call.  */
+  HOST_WIDE_INT constexpr_ops_count;
+  /* Heap VAR_DECLs created during the evaluation of the outermost constant
+     expression.  */
+  auto_vec<tree, 16> heap_vars;
+  /* Constructor.  */
+  constexpr_global_ctx () : constexpr_ops_count (0) {}
+};
+
  /* The constexpr expansion context.  CALL is the current function
     expansion, CTOR is the current aggregate initializer, OBJECT is the
-   object being initialized by CTOR, either a VAR_DECL or a _REF.  VALUES
-   is a map of values of variables initialized within the expression.  */
+   object being initialized by CTOR, either a VAR_DECL or a _REF.    */
struct constexpr_ctx {
+  /* The part of the context that needs to be unique to the whole
+     cxx_eval_outermost_constant_expr invocation.  */
+  constexpr_global_ctx *global;
    /* The innermost call we're evaluating.  */
    constexpr_call *call;
-  /* Values for any temporaries or local variables within the
-     constant-expression. */
-  hash_map<tree,tree> *values;
    /* SAVE_EXPRs that we've seen within the current LOOP_EXPR.  NULL if we
       aren't inside a loop.  */
    vec<tree> *save_exprs;
@@ -1027,10 +1046,6 @@ struct constexpr_ctx {
    tree object;
    /* If inside SWITCH_EXPR.  */
    constexpr_switch_state *css_state;
-  /* Number of cxx_eval_constant_expression calls (except skipped ones,
-     on simple constants or location wrappers) encountered during current
-     cxx_eval_outermost_constant_expr call.  */
-  HOST_WIDE_INT *constexpr_ops_count;
/* Whether we should error on a non-constant expression or fail quietly. */
    bool quiet;
@@ -1656,6 +1671,64 @@ cxx_eval_call_expression (const constexp
                                           lval, non_constant_p, overflow_p);
    if (!DECL_DECLARED_CONSTEXPR_P (fun))
      {
+      if (cxx_dialect >= cxx2a
+         && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fun))
+         && CP_DECL_CONTEXT (fun) == global_namespace)

I'd still like to factor this test out.  OK with that change.

Thanks,
Jason

Reply via email to