re PR c++/48530 ([C++0x][SFINAE] Hard errors with deleted d'tors)
authorJason Merrill <jason@redhat.com>
Tue, 26 Apr 2011 19:28:25 +0000 (15:28 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 26 Apr 2011 19:28:25 +0000 (15:28 -0400)
PR c++/48530
* decl.c (cxx_maybe_build_cleanup): Add complain parm.
* tree.c (force_target_expr): Add complain parm.
(build_target_expr_with_type): Likewise.
(get_target_expr_sfinae): Split out.
(build_vec_init_expr, bot_manip): Adjust.
* init.c (build_vec_delete, build_vec_delete_1): Add complain parm.
(build_delete, build_dtor_call): Likewise.
(perform_direct_initialization_if_possible): Adjust.
(build_vec_init): Handle error return.
* cvt.c (force_rvalue): Add complain parm.
Call build_special_member_call directly.
* decl2.c (delete_sanity): Add complain parm.
(build_cleanup): Adjust.
* pt.c (tsubst_copy_and_build, tsubst_expr): Adjust.
* semantics.c (finish_stmt_expr_expr): Adjust.
(finish_compound_literal): Adjust.
* parser.c (cp_parser_delete_expression): Adjust.
* typeck2.c (build_functional_cast): Adjust.
* cp-tree.h: Adjust.

From-SVN: r172985

14 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/sfinae17.C [new file with mode: 0644]

index cf477a8..fba4a03 100644 (file)
@@ -1,3 +1,26 @@
+2011-04-26  Jason Merrill  <jason@redhat.com>
+
+       PR c++/48530
+       * decl.c (cxx_maybe_build_cleanup): Add complain parm.
+       * tree.c (force_target_expr): Add complain parm.
+       (build_target_expr_with_type): Likewise.
+       (get_target_expr_sfinae): Split out.
+       (build_vec_init_expr, bot_manip): Adjust.
+       * init.c (build_vec_delete, build_vec_delete_1): Add complain parm.
+       (build_delete, build_dtor_call): Likewise.
+       (perform_direct_initialization_if_possible): Adjust.
+       (build_vec_init): Handle error return.
+       * cvt.c (force_rvalue): Add complain parm.
+       Call build_special_member_call directly.
+       * decl2.c (delete_sanity): Add complain parm.
+       (build_cleanup): Adjust.
+       * pt.c (tsubst_copy_and_build, tsubst_expr): Adjust.
+       * semantics.c (finish_stmt_expr_expr): Adjust.
+       (finish_compound_literal): Adjust.
+       * parser.c (cp_parser_delete_expression): Adjust.
+       * typeck2.c (build_functional_cast): Adjust.
+       * cp-tree.h: Adjust.
+
 2011-04-26  Martin Jambor  <mjambor@suse.cz>
 
        * class.c (cp_fold_obj_type_ref): Remove.
index cf8e1a5..10efd1c 100644 (file)
@@ -4144,7 +4144,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
          && TREE_CODE (arg3) != THROW_EXPR)
        {
          if (!VOID_TYPE_P (arg3_type))
-           arg3 = force_rvalue (arg3);
+           {
+             arg3 = force_rvalue (arg3, complain);
+             if (arg3 == error_mark_node)
+               return error_mark_node;
+           }
          arg3_type = TREE_TYPE (arg3);
          result_type = arg3_type;
        }
@@ -4152,7 +4156,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
               && TREE_CODE (arg3) == THROW_EXPR)
        {
          if (!VOID_TYPE_P (arg2_type))
-           arg2 = force_rvalue (arg2);
+           {
+             arg2 = force_rvalue (arg2, complain);
+             if (arg2 == error_mark_node)
+               return error_mark_node;
+           }
          arg2_type = TREE_TYPE (arg2);
          result_type = arg2_type;
        }
@@ -4359,11 +4367,11 @@ build_conditional_expr (tree arg1, tree arg2, tree arg3,
      that isn't wrapped with a TARGET_EXPR plays havoc with exception
      regions.  */
 
-  arg2 = force_rvalue (arg2);
+  arg2 = force_rvalue (arg2, complain);
   if (!CLASS_TYPE_P (arg2_type))
     arg2_type = TREE_TYPE (arg2);
 
-  arg3 = force_rvalue (arg3);
+  arg3 = force_rvalue (arg3, complain);
   if (!CLASS_TYPE_P (arg3_type))
     arg3_type = TREE_TYPE (arg3);
 
@@ -5642,7 +5650,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
                expr = convert_bitfield_to_declared_type (expr);
                expr = fold_convert (type, expr);
              }
-           expr = build_target_expr_with_type (expr, type);
+           expr = build_target_expr_with_type (expr, type, complain);
          }
 
        /* Take the address of the thing to which we will bind the
@@ -6341,7 +6349,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
          if (TREE_CODE (arg) == TARGET_EXPR)
            return arg;
          else if (trivial)
-           return force_target_expr (DECL_CONTEXT (fn), arg);
+           return force_target_expr (DECL_CONTEXT (fn), arg, complain);
        }
       else if (TREE_CODE (arg) == TARGET_EXPR || trivial)
        {
@@ -8246,7 +8254,7 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp)
       if (TREE_STATIC (var))
        init = add_stmt_to_compound (init, register_dtor_fn (var));
       else
-       *cleanup = cxx_maybe_build_cleanup (var);
+       *cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error);
 
       /* We must be careful to destroy the temporary only
         after its initialization has taken place.  If the
index cb04b24..26da4b3 100644 (file)
@@ -4744,7 +4744,7 @@ extern void adjust_clone_args                     (tree);
 /* in cvt.c */
 extern tree convert_to_reference               (tree, tree, int, int, tree);
 extern tree convert_from_reference             (tree);
-extern tree force_rvalue                       (tree);
+extern tree force_rvalue                       (tree, tsubst_flags_t);
 extern tree ocp_convert                                (tree, tree, int, int);
 extern tree cp_convert                         (tree, tree);
 extern tree cp_convert_and_check                (tree, tree);
@@ -4858,7 +4858,7 @@ extern tree next_initializable_field (tree);
 extern bool defer_mark_used_calls;
 extern GTY(()) VEC(tree, gc) *deferred_mark_used_calls;
 extern tree finish_case_label                  (location_t, tree, tree);
-extern tree cxx_maybe_build_cleanup            (tree);
+extern tree cxx_maybe_build_cleanup            (tree, tsubst_flags_t);
 
 /* in decl2.c */
 extern bool check_java_method                  (tree);
@@ -4870,7 +4870,7 @@ extern bool vague_linkage_p                       (tree);
 extern void grokclassfn                                (tree, tree,
                                                 enum overload_flags);
 extern tree grok_array_decl                    (tree, tree);
-extern tree delete_sanity                      (tree, tree, bool, int);
+extern tree delete_sanity                      (tree, tree, bool, int, tsubst_flags_t);
 extern tree check_classfn                      (tree, tree, tree);
 extern void check_member_template              (tree);
 extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *,
@@ -4977,10 +4977,11 @@ extern tree build_vec_init                      (tree, tree, tree, bool, int,
                                                  tsubst_flags_t);
 extern tree build_delete                       (tree, tree,
                                                 special_function_kind,
-                                                int, int);
+                                                int, int, tsubst_flags_t);
 extern void push_base_cleanups                 (void);
 extern tree build_vec_delete                   (tree, tree,
-                                                special_function_kind, int);
+                                                special_function_kind, int,
+                                                tsubst_flags_t);
 extern tree create_temporary_var               (tree);
 extern void initialize_vtbl_ptrs               (tree);
 extern tree build_java_class_ref               (tree);
@@ -5379,8 +5380,8 @@ extern void maybe_add_lambda_conv_op            (tree);
 
 /* in tree.c */
 void cp_free_lang_data                                 (tree t);
-extern tree force_target_expr                  (tree, tree);
-extern tree build_target_expr_with_type                (tree, tree);
+extern tree force_target_expr                  (tree, tree, tsubst_flags_t);
+extern tree build_target_expr_with_type                (tree, tree, tsubst_flags_t);
 extern void lang_check_failed                  (const char *, int,
                                                 const char *) ATTRIBUTE_NORETURN;
 extern tree stabilize_expr                     (tree, tree *);
@@ -5413,6 +5414,7 @@ extern tree build_min_non_dep_call_vec            (tree, tree, VEC(tree,gc) *);
 extern tree build_cplus_new                    (tree, tree, tsubst_flags_t);
 extern tree build_aggr_init_expr               (tree, tree, tsubst_flags_t);
 extern tree get_target_expr                    (tree);
+extern tree get_target_expr_sfinae             (tree, tsubst_flags_t);
 extern tree build_cplus_array_type             (tree, tree);
 extern tree build_array_of_n_type              (tree, int);
 extern tree build_array_copy                   (tree);
index de981bc..64fe871 100644 (file)
@@ -531,11 +531,17 @@ convert_from_reference (tree val)
    argument of class type into a temporary.  */
 
 tree
-force_rvalue (tree expr)
+force_rvalue (tree expr, tsubst_flags_t complain)
 {
-  if (MAYBE_CLASS_TYPE_P (TREE_TYPE (expr)) && TREE_CODE (expr) != TARGET_EXPR)
-    expr = ocp_convert (TREE_TYPE (expr), expr,
-                       CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);
+  tree type = TREE_TYPE (expr);
+  if (MAYBE_CLASS_TYPE_P (type) && TREE_CODE (expr) != TARGET_EXPR)
+    {
+      VEC(tree,gc) *args = make_tree_vector_single (expr);
+      expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
+                                       &args, type, LOOKUP_NORMAL, complain);
+      release_tree_vector (args);
+      expr = build_cplus_new (type, expr, complain);
+    }
   else
     expr = decay_conversion (expr);
 
index dcd18ab..ccc5fd0 100644 (file)
@@ -5640,7 +5640,7 @@ initialize_local_var (tree decl, tree init)
     DECL_READ_P (decl) = 1;
 
   /* Generate a cleanup, if necessary.  */
-  cleanup = cxx_maybe_build_cleanup (decl);
+  cleanup = cxx_maybe_build_cleanup (decl, tf_warning_or_error);
 
   /* Perform the initialization.  */
   if (init)
@@ -13309,7 +13309,7 @@ complete_vars (tree type)
    cleanup need be done.  */
 
 tree
-cxx_maybe_build_cleanup (tree decl)
+cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
 {
   tree type;
   tree attr;
@@ -13344,8 +13344,9 @@ cxx_maybe_build_cleanup (tree decl)
       fn = lookup_name (id);
       arg = build_address (decl);
       mark_used (decl);
-      cleanup = cp_build_function_call_nary (fn, tf_warning_or_error,
-                                            arg, NULL_TREE);
+      cleanup = cp_build_function_call_nary (fn, complain, arg, NULL_TREE);
+      if (cleanup == error_mark_node)
+       return error_mark_node;
     }
   /* Handle ordinary C++ destructors.  */
   type = TREE_TYPE (decl);
@@ -13367,9 +13368,11 @@ cxx_maybe_build_cleanup (tree decl)
        flags |= LOOKUP_NONVIRTUAL;
 
       call = build_delete (TREE_TYPE (addr), addr,
-                          sfk_complete_destructor, flags, 0);
-      if (cleanup)
-       cleanup = build_compound_expr (input_location, cleanup, call);
+                          sfk_complete_destructor, flags, 0, complain);
+      if (call == error_mark_node)
+       cleanup = error_mark_node;
+      else if (cleanup)
+       cleanup = cp_build_compound_expr (cleanup, call, complain);
       else
        cleanup = call;
     }
index a9c2455..d1b252d 100644 (file)
@@ -419,7 +419,8 @@ grok_array_decl (tree array_expr, tree index_exp)
    Implements ARM $5.3.4.  This is called from the parser.  */
 
 tree
-delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete)
+delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete,
+              tsubst_flags_t complain)
 {
   tree t, type;
 
@@ -475,10 +476,11 @@ delete_sanity (tree exp, tree size, bool doing_vec, int use_global_delete)
   if (doing_vec)
     return build_vec_delete (t, /*maxindex=*/NULL_TREE,
                             sfk_deleting_destructor,
-                            use_global_delete);
+                            use_global_delete, complain);
   else
     return build_delete (type, t, sfk_deleting_destructor,
-                        LOOKUP_NORMAL, use_global_delete);
+                        LOOKUP_NORMAL, use_global_delete,
+                        complain);
 }
 
 /* Report an error if the indicated template declaration is not the
@@ -2594,7 +2596,8 @@ build_cleanup (tree decl)
     temp = build_address (decl);
   temp = build_delete (TREE_TYPE (temp), temp,
                       sfk_complete_destructor,
-                      LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+                      LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+                      tf_warning_or_error);
   return temp;
 }
 
index 04d2bb2..25beba8 100644 (file)
@@ -37,7 +37,6 @@ static tree finish_init_stmts (bool, tree, tree);
 static void construct_virtual_base (tree, tree);
 static void expand_aggr_init_1 (tree, tree, tree, tree, int, tsubst_flags_t);
 static void expand_default_init (tree, tree, tree, tree, int, tsubst_flags_t);
-static tree build_vec_delete_1 (tree, tree, tree, special_function_kind, int);
 static void perform_member_init (tree, tree);
 static tree build_builtin_delete_call (tree);
 static int member_init_ok_or_else (tree, tree, tree);
@@ -46,7 +45,6 @@ static tree sort_mem_initializers (tree, tree);
 static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
-static tree build_dtor_call (tree, special_function_kind, int);
 static tree build_field_list (tree, tree, int *);
 static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
@@ -620,7 +618,8 @@ perform_member_init (tree member, tree init)
                                             /*preserve_reference=*/false,
                                             tf_warning_or_error);
       expr = build_delete (type, expr, sfk_complete_destructor,
-                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+                          LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0,
+                          tf_warning_or_error);
 
       if (expr != error_mark_node)
        finish_eh_cleanup (expr);
@@ -2720,7 +2719,8 @@ build_java_class_ref (tree type)
 \f
 static tree
 build_vec_delete_1 (tree base, tree maxindex, tree type,
-    special_function_kind auto_delete_vec, int use_global_delete)
+                   special_function_kind auto_delete_vec,
+                   int use_global_delete, tsubst_flags_t complain)
 {
   tree virtual_size;
   tree ptype = build_pointer_type (type = complete_type (type));
@@ -2749,6 +2749,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
   /* We should only have 1-D arrays here.  */
   gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
 
+  if (base == error_mark_node || maxindex == error_mark_node)
+    return error_mark_node;
+
   if (! MAYBE_CLASS_TYPE_P (type) || TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     goto no_destructor;
 
@@ -2762,7 +2765,9 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
                                                  POINTER_PLUS_EXPR, ptype,
                                                  fold_convert (ptype, base),
                                                  virtual_size),
-                                    tf_warning_or_error);
+                                    complain);
+  if (tbase_init == error_mark_node)
+    return error_mark_node;
   controller = build3 (BIND_EXPR, void_type_node, tbase,
                       NULL_TREE, NULL_TREE);
   TREE_SIDE_EFFECTS (controller) = 1;
@@ -2771,15 +2776,17 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
                 build2 (EQ_EXPR, boolean_type_node, tbase,
                         fold_convert (ptype, base)));
   tmp = fold_build1_loc (input_location, NEGATE_EXPR, sizetype, size_exp);
-  body = build_compound_expr
-    (input_location, 
-     body, cp_build_modify_expr (tbase, NOP_EXPR,
-                                build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp),
-                                tf_warning_or_error));
-  body = build_compound_expr
-    (input_location,
-     body, build_delete (ptype, tbase, sfk_complete_destructor,
-                        LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1));
+  tmp = build2 (POINTER_PLUS_EXPR, ptype, tbase, tmp);
+  tmp = cp_build_modify_expr (tbase, NOP_EXPR, tmp, complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
+  tmp = build_delete (ptype, tbase, sfk_complete_destructor,
+                     LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1,
+                     complain);
+  if (tmp == error_mark_node)
+    return error_mark_node;
+  body = build_compound_expr (input_location, body, tmp);
 
   loop = build1 (LOOP_EXPR, void_type_node, body);
   loop = build_compound_expr (input_location, tbase_init, loop);
@@ -2803,14 +2810,15 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
          tree cookie_size;
 
          cookie_size = targetm.cxx.get_cookie_size (type);
-         base_tbd
-           = cp_convert (ptype,
-                         cp_build_binary_op (input_location,
-                                             MINUS_EXPR,
-                                             cp_convert (string_type_node,
-                                                         base),
-                                             cookie_size,
-                                             tf_warning_or_error));
+         base_tbd = cp_build_binary_op (input_location,
+                                        MINUS_EXPR,
+                                        cp_convert (string_type_node,
+                                                    base),
+                                        cookie_size,
+                                        complain);
+         if (base_tbd == error_mark_node)
+           return error_mark_node;
+         base_tbd = cp_convert (ptype, base_tbd);
          /* True size with header.  */
          virtual_size = size_binop (PLUS_EXPR, virtual_size, cookie_size);
        }
@@ -2853,7 +2861,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
     /* Pre-evaluate the SAVE_EXPR outside of the BIND_EXPR.  */
     body = build2 (COMPOUND_EXPR, void_type_node, base, body);
 
-  return convert_to_void (body, ICV_CAST, tf_warning_or_error);
+  return convert_to_void (body, ICV_CAST, complain);
 }
 
 /* Create an unnamed variable of the indicated TYPE.  */
@@ -2942,6 +2950,7 @@ build_vec_init (tree base, tree maxindex, tree init,
   tree const_init = NULL_TREE;
   tree obase = base;
   bool xvalue = false;
+  bool errors = false;
 
   if (TREE_CODE (atype) == ARRAY_TYPE && TYPE_DOMAIN (atype))
     maxindex = array_type_nelts (atype);
@@ -3087,7 +3096,8 @@ build_vec_init (tree base, tree maxindex, tree init,
          else
            one_init = cp_build_modify_expr (baseref, NOP_EXPR,
                                             elt, complain);
-
+         if (one_init == error_mark_node)
+           errors = true;
          if (try_const)
            {
              tree e = one_init;
@@ -3120,10 +3130,18 @@ build_vec_init (tree base, tree maxindex, tree init,
            finish_expr_stmt (one_init);
          current_stmt_tree ()->stmts_are_full_exprs_p = 0;
 
-         finish_expr_stmt (cp_build_unary_op (PREINCREMENT_EXPR, base, 0,
-                                               complain));
-         finish_expr_stmt (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                               complain));
+         one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, 0, complain);
+         if (one_init == error_mark_node)
+           errors = true;
+         else
+           finish_expr_stmt (one_init);
+
+         one_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                       complain);
+         if (one_init == error_mark_node)
+           errors = true;
+         else
+           finish_expr_stmt (one_init);
        }
 
       if (try_const)
@@ -3149,7 +3167,7 @@ build_vec_init (tree base, tree maxindex, tree init,
        {
           if (complain & tf_error)
             error ("initializer ends prematurely");
-         return error_mark_node;
+         errors = true;
        }
     }
 
@@ -3176,9 +3194,11 @@ build_vec_init (tree base, tree maxindex, tree init,
       finish_for_cond (build2 (NE_EXPR, boolean_type_node, iterator,
                               build_int_cst (TREE_TYPE (iterator), -1)),
                       for_stmt);
-      finish_for_expr (cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
-                                          complain),
-                      for_stmt);
+      elt_init = cp_build_unary_op (PREDECREMENT_EXPR, iterator, 0,
+                                   complain);
+      if (elt_init == error_mark_node)
+       errors = true;
+      finish_for_expr (elt_init, for_stmt);
 
       to = build1 (INDIRECT_REF, type, base);
 
@@ -3219,9 +3239,7 @@ build_vec_init (tree base, tree maxindex, tree init,
       else if (explicit_value_init_p)
        {
          elt_init = build_value_init (type, complain);
-         if (elt_init == error_mark_node)
-           return error_mark_node;
-         else
+         if (elt_init != error_mark_node)
            elt_init = build2 (INIT_EXPR, type, to, elt_init);
        }
       else
@@ -3230,6 +3248,9 @@ build_vec_init (tree base, tree maxindex, tree init,
          elt_init = build_aggr_init (to, init, 0, complain);
        }
 
+      if (elt_init == error_mark_node)
+       errors = true;
+
       current_stmt_tree ()->stmts_are_full_exprs_p = 1;
       finish_expr_stmt (elt_init);
       current_stmt_tree ()->stmts_are_full_exprs_p = 0;
@@ -3263,7 +3284,9 @@ build_vec_init (tree base, tree maxindex, tree init,
       finish_cleanup_try_block (try_block);
       e = build_vec_delete_1 (rval, m,
                              inner_elt_type, sfk_base_destructor,
-                             /*use_global_delete=*/0);
+                             /*use_global_delete=*/0, complain);
+      if (e == error_mark_node)
+       errors = true;
       finish_cleanup (e, try_block);
     }
 
@@ -3286,6 +3309,8 @@ build_vec_init (tree base, tree maxindex, tree init,
 
   if (const_init)
     return build2 (INIT_EXPR, atype, obase, const_init);
+  if (errors)
+    return error_mark_node;
   return stmt_expr;
 }
 
@@ -3293,7 +3318,8 @@ build_vec_init (tree base, tree maxindex, tree init,
    build_delete.  */
 
 static tree
-build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
+build_dtor_call (tree exp, special_function_kind dtor_kind, int flags,
+                tsubst_flags_t complain)
 {
   tree name;
   tree fn;
@@ -3320,7 +3346,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
                                /*conversion_path=*/NULL_TREE,
                                flags,
                                /*fn_p=*/NULL,
-                               tf_warning_or_error);
+                               complain);
 }
 
 /* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3334,7 +3360,7 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
 
 tree
 build_delete (tree type, tree addr, special_function_kind auto_delete,
-    int flags, int use_global_delete)
+             int flags, int use_global_delete, tsubst_flags_t complain)
 {
   tree expr;
 
@@ -3369,8 +3395,9 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
          complete_type (type);
          if (!COMPLETE_TYPE_P (type))
            {
-             if (warning (0, "possible problem detected in invocation of "
-                          "delete operator:"))
+             if ((complain & tf_warning)
+                 && warning (0, "possible problem detected in invocation of "
+                             "delete operator:"))
                {
                  cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
                  inform (input_location, "neither the destructor nor the class-specific "
@@ -3395,18 +3422,21 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
 
       if (TYPE_DOMAIN (type) == NULL_TREE)
        {
-         error ("unknown array size in delete");
+         if (complain & tf_error)
+           error ("unknown array size in delete");
          return error_mark_node;
        }
       return build_vec_delete (addr, array_type_nelts (type),
-                              auto_delete, use_global_delete);
+                              auto_delete, use_global_delete, complain);
     }
   else
     {
       /* Don't check PROTECT here; leave that decision to the
         destructor.  If the destructor is accessible, call it,
         else report error.  */
-      addr = cp_build_addr_expr (addr, tf_warning_or_error);
+      addr = cp_build_addr_expr (addr, complain);
+      if (addr == error_mark_node)
+       return error_mark_node;
       if (TREE_SIDE_EFFECTS (addr))
        addr = save_expr (addr);
 
@@ -3478,9 +3508,10 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
                                /*alloc_fn=*/NULL_TREE);
        }
 
-      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, 
-                                                     tf_warning_or_error),
-                             auto_delete, flags);
+      expr = build_dtor_call (cp_build_indirect_ref (addr, RO_NULL, complain),
+                             auto_delete, flags, complain);
+      if (expr == error_mark_node)
+       return error_mark_node;
       if (do_delete)
        expr = build2 (COMPOUND_EXPR, void_type_node, expr, do_delete);
 
@@ -3492,10 +3523,14 @@ build_delete (tree type, tree addr, special_function_kind auto_delete,
        /* Explicit destructor call; don't check for null pointer.  */
        ifexp = integer_one_node;
       else
-       /* Handle deleting a null pointer.  */
-       ifexp = fold (cp_build_binary_op (input_location,
-                                         NE_EXPR, addr, integer_zero_node,
-                                         tf_warning_or_error));
+       {
+         /* Handle deleting a null pointer.  */
+         ifexp = fold (cp_build_binary_op (input_location,
+                                           NE_EXPR, addr, integer_zero_node,
+                                           complain));
+         if (ifexp == error_mark_node)
+           return error_mark_node;
+       }
 
       if (ifexp != integer_one_node)
        expr = build3 (COND_EXPR, void_type_node,
@@ -3588,7 +3623,7 @@ push_base_cleanups (void)
          expr = build_delete (this_type, this_member,
                               sfk_complete_destructor,
                               LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL,
-                              0);
+                              0, tf_warning_or_error);
          finish_decl_cleanup (NULL_TREE, expr);
        }
     }
@@ -3612,7 +3647,8 @@ push_base_cleanups (void)
 
 tree
 build_vec_delete (tree base, tree maxindex,
-    special_function_kind auto_delete_vec, int use_global_delete)
+                 special_function_kind auto_delete_vec,
+                 int use_global_delete, tsubst_flags_t complain)
 {
   tree type;
   tree rval;
@@ -3638,7 +3674,7 @@ build_vec_delete (tree base, tree maxindex,
                            size_ptr_type,
                            fold_convert (size_ptr_type, base),
                            cookie_addr);
-      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, tf_warning_or_error);
+      maxindex = cp_build_indirect_ref (cookie_addr, RO_NULL, complain);
     }
   else if (TREE_CODE (type) == ARRAY_TYPE)
     {
@@ -3646,7 +3682,9 @@ build_vec_delete (tree base, tree maxindex,
         bad name.  */
       maxindex = array_type_nelts_total (type);
       type = strip_array_types (type);
-      base = cp_build_addr_expr (base, tf_warning_or_error);
+      base = cp_build_addr_expr (base, complain);
+      if (base == error_mark_node)
+       return error_mark_node;
       if (TREE_SIDE_EFFECTS (base))
        {
          base_init = get_target_expr (base);
@@ -3655,14 +3693,14 @@ build_vec_delete (tree base, tree maxindex,
     }
   else
     {
-      if (base != error_mark_node)
+      if (base != error_mark_node && !(complain & tf_error))
        error ("type to vector delete is neither pointer or array type");
       return error_mark_node;
     }
 
   rval = build_vec_delete_1 (base, maxindex, type, auto_delete_vec,
-                            use_global_delete);
-  if (base_init)
+                            use_global_delete, complain);
+  if (base_init && rval != error_mark_node)
     rval = build2 (COMPOUND_EXPR, TREE_TYPE (rval), base_init, rval);
 
   return rval;
index bb97700..6da285e 100644 (file)
@@ -6295,7 +6295,8 @@ cp_parser_delete_expression (cp_parser* parser)
   if (cp_parser_non_integral_constant_expression (parser, NIC_DEL))
     return error_mark_node;
 
-  return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
+  return delete_sanity (expression, NULL_TREE, array_p, global_scope_p,
+                       tf_warning_or_error);
 }
 
 /* Returns true if TOKEN may start a cast-expression and false
index 654289a..de574a4 100644 (file)
@@ -12102,7 +12102,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
                            init = build_value_init (TREE_TYPE (decl),
                                                     complain);
                            if (TREE_CODE (init) == AGGR_INIT_EXPR)
-                             init = get_target_expr (init);
+                             init = get_target_expr_sfinae (init, complain);
                          }
                        else
                          init = t;
@@ -12846,7 +12846,8 @@ tsubst_copy_and_build (tree t,
        (RECUR (TREE_OPERAND (t, 0)),
        RECUR (TREE_OPERAND (t, 1)),
        DELETE_EXPR_USE_VEC (t),
-       DELETE_EXPR_USE_GLOBAL (t));
+       DELETE_EXPR_USE_GLOBAL (t),
+       complain);
 
     case COMPOUND_EXPR:
       return build_x_compound_expr (RECUR (TREE_OPERAND (t, 0)),
index 62272aa..16fabb8 100644 (file)
@@ -1835,7 +1835,7 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
          /* It actually has a value we need to deal with.  First, force it
             to be an rvalue so that we won't need to build up a copy
             constructor call later when we try to assign it to something.  */
-         expr = force_rvalue (expr);
+         expr = force_rvalue (expr, tf_warning_or_error);
          if (error_operand_p (expr))
            return error_mark_node;
 
@@ -1892,7 +1892,7 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
         temporary object created by the final expression is destroyed at
         the end of the full-expression containing the
         statement-expression.  */
-      result = force_target_expr (type, result);
+      result = force_target_expr (type, result, tf_warning_or_error);
     }
 
   return result;
@@ -2407,7 +2407,7 @@ finish_compound_literal (tree type, tree compound_literal,
       return decl;
     }
   else
-    return get_target_expr (compound_literal);
+    return get_target_expr_sfinae (compound_literal, complain);
 }
 
 /* Return the declaration for the function-name variable indicated by
@@ -7995,7 +7995,7 @@ build_lambda_object (tree lambda_expr)
             There's normally no way to express direct-initialization
             from an element of a CONSTRUCTOR, so we build up a special
             TARGET_EXPR to bypass the usual copy-initialization.  */
-         val = force_rvalue (val);
+         val = force_rvalue (val, tf_warning_or_error);
          if (TREE_CODE (val) == TARGET_EXPR)
            TARGET_EXPR_DIRECT_INIT_P (val) = true;
        }
index fd5c55e..8fe8832 100644 (file)
@@ -39,7 +39,7 @@ static tree bot_replace (tree *, int *, void *);
 static int list_hash_eq (const void *, const void *);
 static hashval_t list_hash_pieces (tree, tree, tree);
 static hashval_t list_hash (const void *);
-static tree build_target_expr (tree, tree);
+static tree build_target_expr (tree, tree, tsubst_flags_t);
 static tree count_trees_r (tree *, int *, void *);
 static tree verify_stmt_tree_r (tree *, int *, void *);
 static tree build_local_temp (tree);
@@ -281,7 +281,7 @@ builtin_valid_in_constant_expr_p (const_tree decl)
 /* Build a TARGET_EXPR, initializing the DECL with the VALUE.  */
 
 static tree
-build_target_expr (tree decl, tree value)
+build_target_expr (tree decl, tree value, tsubst_flags_t complain)
 {
   tree t;
 
@@ -292,8 +292,10 @@ build_target_expr (tree decl, tree value)
                                            TREE_TYPE (value)));
 #endif
 
-  t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value,
-             cxx_maybe_build_cleanup (decl), NULL_TREE);
+  t = cxx_maybe_build_cleanup (decl, complain);
+  if (t == error_mark_node)
+    return error_mark_node;
+  t = build4 (TARGET_EXPR, TREE_TYPE (decl), decl, value, t, NULL_TREE);
   /* We always set TREE_SIDE_EFFECTS so that expand_expr does not
      ignore the TARGET_EXPR.  If there really turn out to be no
      side-effects, then the optimizer should be able to get rid of
@@ -453,7 +455,7 @@ build_cplus_new (tree type, tree init, tsubst_flags_t complain)
   else
     return rval;
 
-  rval = build_target_expr (slot, rval);
+  rval = build_target_expr (slot, rval, complain);
   TARGET_EXPR_IMPLICIT_P (rval) = 1;
 
   return rval;
@@ -526,7 +528,7 @@ build_vec_init_expr (tree type, tree init)
     VEC_INIT_EXPR_IS_CONSTEXPR (init) = true;
   VEC_INIT_EXPR_VALUE_INIT (init) = value_init;
 
-  init = build_target_expr (slot, init);
+  init = build_target_expr (slot, init, tf_warning_or_error);
   TARGET_EXPR_IMPLICIT_P (init) = 1;
 
   return init;
@@ -559,7 +561,7 @@ build_array_copy (tree init)
    indicated TYPE.  */
 
 tree
-build_target_expr_with_type (tree init, tree type)
+build_target_expr_with_type (tree init, tree type, tsubst_flags_t complain)
 {
   gcc_assert (!VOID_TYPE_P (type));
 
@@ -577,9 +579,9 @@ build_target_expr_with_type (tree init, tree type)
        another one here.  A CONSTRUCTOR is aggregate initialization, which
        is handled separately.  A VA_ARG_EXPR is magic creation of an
        aggregate; there's no additional work to be done.  */
-    return force_rvalue (init);
+    return force_rvalue (init, complain);
 
-  return force_target_expr (type, init);
+  return force_target_expr (type, init, complain);
 }
 
 /* Like the above function, but without the checking.  This function should
@@ -588,27 +590,33 @@ build_target_expr_with_type (tree init, tree type)
    infinite recursion.  */
 
 tree
-force_target_expr (tree type, tree init)
+force_target_expr (tree type, tree init, tsubst_flags_t complain)
 {
   tree slot;
 
   gcc_assert (!VOID_TYPE_P (type));
 
   slot = build_local_temp (type);
-  return build_target_expr (slot, init);
+  return build_target_expr (slot, init, complain);
 }
 
 /* Like build_target_expr_with_type, but use the type of INIT.  */
 
 tree
-get_target_expr (tree init)
+get_target_expr_sfinae (tree init, tsubst_flags_t complain)
 {
   if (TREE_CODE (init) == AGGR_INIT_EXPR)
-    return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init);
+    return build_target_expr (AGGR_INIT_EXPR_SLOT (init), init, complain);
   else if (TREE_CODE (init) == VEC_INIT_EXPR)
-    return build_target_expr (VEC_INIT_EXPR_SLOT (init), init);
+    return build_target_expr (VEC_INIT_EXPR_SLOT (init), init, complain);
   else
-    return build_target_expr_with_type (init, TREE_TYPE (init));
+    return build_target_expr_with_type (init, TREE_TYPE (init), complain);
+}
+
+tree
+get_target_expr (tree init)
+{
+  return get_target_expr_sfinae (init, tf_warning_or_error);
 }
 
 /* If EXPR is a bitfield reference, convert it to the declared type of
@@ -1810,7 +1818,8 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
        u = build_cplus_new (TREE_TYPE (t), TREE_OPERAND (t, 1),
                             tf_warning_or_error);
       else
-       u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t));
+       u = build_target_expr_with_type (TREE_OPERAND (t, 1), TREE_TYPE (t),
+                                        tf_warning_or_error);
 
       /* Map the old variable to the new one.  */
       splay_tree_insert (target_remap,
index 49f4e7e..5522868 100644 (file)
@@ -1610,7 +1610,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
       && !TYPE_HAS_USER_CONSTRUCTOR (type))
     {
       exp = build_value_init (type, complain);
-      exp = get_target_expr (exp);
+      exp = get_target_expr_sfinae (exp, complain);
       /* FIXME this is wrong */
       if (literal_type_p (type))
        TREE_CONSTANT (exp) = true;
index f6533ca..0a59e37 100644 (file)
@@ -1,3 +1,7 @@
+2011-04-25  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/sfinae17.C: New.
+
 2011-03-23  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        PR target/48258
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae17.C b/gcc/testsuite/g++.dg/cpp0x/sfinae17.C
new file mode 100644 (file)
index 0000000..dbbd9ef
--- /dev/null
@@ -0,0 +1,31 @@
+// PR c++/48530
+// { dg-options -std=c++0x }
+
+template<class T,
+        class = decltype(T{})
+>
+char f(int);
+
+template<class>
+char (&f(...))[2];
+
+struct DelDtor {
+  ~DelDtor() = delete;
+};
+
+static_assert(sizeof(f<DelDtor[2]>(0)) != 1, "Error");
+
+struct A
+{
+  static DelDtor *p;
+};
+
+template<class T,
+        class = decltype(delete T::p, (T*)0)
+>
+char g(int);
+
+template<class>
+char (&g(...))[2];
+
+static_assert(sizeof(g<DelDtor>(0)) != 1, "Error");