]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cp/cvt.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / cp / cvt.c
index 5264c5df2a810f1b69731bceb47fb1ea22411286..c10db92bd6f31ecf2aabf38025502bf62682fcbc 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-level data type conversion for GNU C++.
-   Copyright (C) 1987-2013 Free Software Foundation, Inc.
+   Copyright (C) 1987-2019 Free Software Foundation, Inc.
    Hacked by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GCC.
@@ -27,17 +27,15 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "target.h"
+#include "cp-tree.h"
 #include "stor-layout.h"
 #include "flags.h"
-#include "cp-tree.h"
 #include "intl.h"
 #include "convert.h"
-#include "decl.h"
-#include "target.h"
+#include "stringpool.h"
+#include "attribs.h"
 
-static tree cp_convert_to_pointer (tree, tree, tsubst_flags_t);
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
 static tree build_up_reference (tree, tree, int, tree, tsubst_flags_t);
@@ -53,7 +51,7 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
 
    Here is a list of all the functions that assume that widening and
    narrowing is always done with a NOP_EXPR:
-     In convert.c, convert_to_integer.
+     In convert.c, convert_to_integer[_maybe_fold].
      In c-typeck.c, build_binary_op_nodefault (boolean ops),
        and c_common_truthvalue_conversion.
      In expr.c: expand_expr, for operands of a MULT_EXPR.
@@ -73,12 +71,13 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
    else try C-style pointer conversion.  */
 
 static tree
-cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
+cp_convert_to_pointer (tree type, tree expr, bool dofold,
+                      tsubst_flags_t complain)
 {
   tree intype = TREE_TYPE (expr);
   enum tree_code form;
   tree rval;
-  location_t loc = EXPR_LOC_OR_HERE (expr);
+  location_t loc = cp_expr_loc_or_loc (expr, input_location);
 
   if (intype == error_mark_node)
     return error_mark_node;
@@ -89,7 +88,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
       if (!COMPLETE_TYPE_P (intype))
        {
          if (complain & tf_error)
-           error_at (loc, "can%'t convert from incomplete type %qT to %qT",
+           error_at (loc, "can%'t convert from incomplete type %qH to %qI",
                      intype, type);
          return error_mark_node;
        }
@@ -99,7 +98,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
        {
          if ((complain & tf_error)
              && rval == error_mark_node)
-           error_at (loc, "conversion of %qE from %qT to %qT is ambiguous",
+           error_at (loc, "conversion of %qE from %qH to %qI is ambiguous",
                      expr, intype, type);
          return rval;
        }
@@ -123,7 +122,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
 
   form = TREE_CODE (intype);
 
-  if (POINTER_TYPE_P (intype))
+  if (INDIRECT_TYPE_P (intype))
     {
       intype = TYPE_MAIN_VARIANT (intype);
 
@@ -171,7 +170,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
       if (TYPE_PTRMEMFUNC_P (type))
        {
          if (complain & tf_error)
-           error_at (loc, "cannot convert %qE from type %qT to type %qT",
+           error_at (loc, "cannot convert %qE from type %qH to type %qI",
                      expr, intype, type);
          return error_mark_node;
        }
@@ -188,7 +187,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
        {
          if (TREE_CODE (expr) == PTRMEM_CST)
            return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr),
-                                         complain);
+                                         dofold, complain);
          else if (TREE_CODE (expr) == OFFSET_REF)
            {
              tree object = TREE_OPERAND (expr, 0);
@@ -197,8 +196,9 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
                                                       complain);
            }
        }
-      error_at (loc, "cannot convert %qE from type %qT to type %qT",
-               expr, intype, type);
+      if (complain & tf_error)
+       error_at (loc, "cannot convert %qE from type %qH to type %qI",
+                 expr, intype, type);
       return error_mark_node;
     }
 
@@ -223,7 +223,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
   else if (TYPE_PTRMEM_P (type) && INTEGRAL_CODE_P (form))
     {
       if (complain & tf_error)
-       error_at (loc, "invalid conversion from %qT to %qT", intype, type);
+       error_at (loc, "invalid conversion from %qH to %qI", intype, type);
       return error_mark_node;
     }
 
@@ -236,17 +236,22 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
       /* Modes may be different but sizes should be the same.  There
         is supposed to be some integral type that is the same width
         as a pointer.  */
-      gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
-                 == GET_MODE_SIZE (TYPE_MODE (type)));
+      gcc_assert (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (expr)))
+                 == GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type)));
 
-      return convert_to_pointer (type, expr);
+      /* FIXME needed because convert_to_pointer_maybe_fold still folds
+        conversion of constants.  */
+      if (!dofold)
+       return build1 (CONVERT_EXPR, type, expr);
+
+      return convert_to_pointer_maybe_fold (type, expr, dofold);
     }
 
   if (type_unknown_p (expr))
     return instantiate_type (type, expr, complain);
 
   if (complain & tf_error)
-    error_at (loc, "cannot convert %qE from type %qT to type %qT",
+    error_at (loc, "cannot convert %qE from type %qH to type %qI",
              expr, intype, type);
   return error_mark_node;
 }
@@ -298,7 +303,7 @@ convert_to_pointer_force (tree type, tree expr, tsubst_flags_t complain)
        }
     }
 
-  return cp_convert_to_pointer (type, expr, complain);
+  return cp_convert_to_pointer (type, expr, /*fold*/false, complain);
 }
 
 /* We are passing something to a function which requires a reference.
@@ -317,9 +322,9 @@ build_up_reference (tree type, tree arg, int flags, tree decl,
   tree argtype = TREE_TYPE (arg);
   tree target_type = TREE_TYPE (type);
 
-  gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
+  gcc_assert (TYPE_REF_P (type));
 
-  if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg))
+  if ((flags & DIRECT_BIND) && ! lvalue_p (arg))
     {
       /* Create a new temporary variable.  We can't just use a TARGET_EXPR
         here because it needs to live as long as DECL.  */
@@ -332,7 +337,7 @@ build_up_reference (tree type, tree arg, int flags, tree decl,
       cp_finish_decl (arg, targ, /*init_const_expr_p=*/false, NULL_TREE,
                      LOOKUP_ONLYCONVERTING|DIRECT_BIND);
     }
-  else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
+  else if (!(flags & DIRECT_BIND) && ! obvalue_p (arg))
     return get_target_expr_sfinae (arg, complain);
 
   /* If we had a way to wrap this up, and say, if we ever needed its
@@ -376,7 +381,8 @@ diagnose_ref_binding (location_t loc, tree reftype, tree intype, tree decl)
 {
   tree ttl = TREE_TYPE (reftype);
 
-  if (!CP_TYPE_CONST_NON_VOLATILE_P (ttl))
+  if (!TYPE_REF_IS_RVALUE (reftype)
+      && !CP_TYPE_CONST_NON_VOLATILE_P (ttl))
     {
       const char *msg;
 
@@ -413,7 +419,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
   tree rval = NULL_TREE;
   tree rval_as_conversion = NULL_TREE;
   bool can_convert_intype_to_type;
-  location_t loc = EXPR_LOC_OR_HERE (expr);
+  location_t loc = cp_expr_loc_or_loc (expr, input_location);
 
   if (TREE_CODE (type) == FUNCTION_TYPE
       && TREE_TYPE (expr) == unknown_type_node)
@@ -424,8 +430,8 @@ convert_to_reference (tree reftype, tree expr, int convtype,
 
   intype = TREE_TYPE (expr);
 
-  gcc_assert (TREE_CODE (intype) != REFERENCE_TYPE);
-  gcc_assert (TREE_CODE (reftype) == REFERENCE_TYPE);
+  gcc_assert (!TYPE_REF_P (intype));
+  gcc_assert (TYPE_REF_P (reftype));
 
   intype = TYPE_MAIN_VARIANT (intype);
 
@@ -441,7 +447,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
        = build_type_conversion (reftype, expr);
 
       if (rval_as_conversion && rval_as_conversion != error_mark_node
-         && real_lvalue_p (rval_as_conversion))
+         && lvalue_p (rval_as_conversion))
        {
          expr = rval_as_conversion;
          rval_as_conversion = NULL_TREE;
@@ -459,14 +465,14 @@ convert_to_reference (tree reftype, tree expr, int convtype,
        tree ttr = lvalue_type (expr);
 
        if ((complain & tf_error)
-           && ! real_lvalue_p (expr))
+           && ! lvalue_p (expr))
          diagnose_ref_binding (loc, reftype, intype, decl);
 
        if (! (convtype & CONV_CONST)
            && !at_least_as_qualified_p (ttl, ttr))
          {
            if (complain & tf_error)
-             permerror (loc, "conversion from %qT to %qT discards qualifiers",
+             permerror (loc, "conversion from %qH to %qI discards qualifiers",
                         ttr, reftype);
            else
              return error_mark_node;
@@ -475,7 +481,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
 
       return build_up_reference (reftype, expr, flags, decl, complain);
     }
-  else if ((convtype & CONV_REINTERPRET) && lvalue_p (expr))
+  else if ((convtype & CONV_REINTERPRET) && obvalue_p (expr))
     {
       /* When casting an lvalue to a reference type, just convert into
         a pointer to the new type and deference it.  This is allowed
@@ -516,7 +522,7 @@ convert_to_reference (tree reftype, tree expr, int convtype,
     }
 
   if (complain & tf_error)
-    error_at (loc, "cannot convert type %qT to type %qT", intype, reftype);
+    error_at (loc, "cannot convert type %qH to type %qI", intype, reftype);
 
   return error_mark_node;
 }
@@ -528,7 +534,7 @@ tree
 convert_from_reference (tree val)
 {
   if (TREE_TYPE (val)
-      && TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
+      && TYPE_REF_P (TREE_TYPE (val)))
     {
       tree t = TREE_TYPE (TREE_TYPE (val));
       tree ref = build1 (INDIRECT_REF, t, val);
@@ -576,17 +582,20 @@ force_rvalue (tree expr, tsubst_flags_t complain)
 static tree
 ignore_overflows (tree expr, tree orig)
 {
-  if (TREE_CODE (expr) == INTEGER_CST
-      && TREE_CODE (orig) == INTEGER_CST
-      && TREE_OVERFLOW (expr) != TREE_OVERFLOW (orig))
+  tree stripped_expr = tree_strip_any_location_wrapper (expr);
+  tree stripped_orig = tree_strip_any_location_wrapper (orig);
+
+  if (TREE_CODE (stripped_expr) == INTEGER_CST
+      && TREE_CODE (stripped_orig) == INTEGER_CST
+      && TREE_OVERFLOW (stripped_expr) != TREE_OVERFLOW (stripped_orig))
     {
-      gcc_assert (!TREE_OVERFLOW (orig));
+      gcc_assert (!TREE_OVERFLOW (stripped_orig));
       /* Ensure constant sharing.  */
-      expr = build_int_cst_wide (TREE_TYPE (expr),
-                                TREE_INT_CST_LOW (expr),
-                                TREE_INT_CST_HIGH (expr));
+      stripped_expr = wide_int_to_tree (TREE_TYPE (stripped_expr),
+                                       wi::to_wide (stripped_expr));
     }
-  return expr;
+
+  return preserve_any_location_wrapper (stripped_expr, expr);
 }
 
 /* Fold away simple conversions, but make sure TREE_OVERFLOW is set
@@ -595,8 +604,28 @@ ignore_overflows (tree expr, tree orig)
 tree
 cp_fold_convert (tree type, tree expr)
 {
-  tree conv = fold_convert (type, expr);
-  conv = ignore_overflows (conv, expr);
+  tree conv;
+  if (TREE_TYPE (expr) == type)
+    conv = expr;
+  else if (TREE_CODE (expr) == PTRMEM_CST
+          && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type),
+                          PTRMEM_CST_CLASS (expr)))
+    {
+      /* Avoid wrapping a PTRMEM_CST in NOP_EXPR.  */
+      conv = copy_node (expr);
+      TREE_TYPE (conv) = type;
+    }
+  else if (TYPE_PTRMEM_P (type))
+    {
+      conv = convert_ptrmem (type, expr, true, false,
+                            tf_warning_or_error);
+      conv = cp_fully_fold (conv);
+    }
+  else
+    {
+      conv = fold_convert (type, expr);
+      conv = ignore_overflows (conv, expr);
+    }
   return conv;
 }
 
@@ -622,23 +651,29 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
 
   if (TREE_TYPE (expr) == type)
     return expr;
-  
+  if (expr == error_mark_node)
+    return expr;
   result = cp_convert (type, expr, complain);
 
   if ((complain & tf_warning)
       && c_inhibit_evaluation_warnings == 0)
     {
-      tree folded = maybe_constant_value (expr);
-      tree stripped = folded;
-      tree folded_result = cp_convert (type, folded, complain);
-
-      /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
-        NOP_EXPR so that it isn't TREE_CONSTANT anymore.  */
-      STRIP_NOPS (stripped);
-
-      if (!TREE_OVERFLOW_P (stripped)
+      tree folded = cp_fully_fold (expr);
+      tree folded_result;
+      if (folded == expr)
+       folded_result = result;
+      else
+       {
+         /* Avoid bogus -Wparentheses warnings.  */
+         warning_sentinel w (warn_parentheses);
+         warning_sentinel c (warn_int_in_bool_context);
+         folded_result = cp_convert (type, folded, tf_none);
+       }
+      folded_result = fold_simple (folded_result);
+      if (!TREE_OVERFLOW_P (folded)
          && folded_result != error_mark_node)
-       warnings_for_convert_and_check (type, folded, folded_result);
+       warnings_for_convert_and_check (cp_expr_loc_or_loc (expr, input_location),
+                                       type, folded, folded_result);
     }
 
   return result;
@@ -656,7 +691,8 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
   enum tree_code code = TREE_CODE (type);
   const char *invalid_conv_diag;
   tree e1;
-  location_t loc = EXPR_LOC_OR_HERE (expr);
+  location_t loc = cp_expr_loc_or_loc (expr, input_location);
+  bool dofold = (convtype & CONV_FOLD);
 
   if (error_operand_p (e) || type == error_mark_node)
     return error_mark_node;
@@ -673,17 +709,29 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
     }
 
   /* FIXME remove when moving to c_fully_fold model.  */
-  /* FIXME do we still need this test?  */
   if (!CLASS_TYPE_P (type))
-    e = integral_constant_value (e);
+    {
+      e = mark_rvalue_use (e);
+      e = scalar_constant_value (e);
+    }
   if (error_operand_p (e))
     return error_mark_node;
 
+  if (NULLPTR_TYPE_P (type) && null_ptr_cst_p (e))
+    {
+      if (complain & tf_warning)
+       maybe_warn_zero_as_null_pointer_constant (e, loc);
+
+      if (!TREE_SIDE_EFFECTS (e))
+       return nullptr_node;
+    }
+
   if (MAYBE_CLASS_TYPE_P (type) && (convtype & CONV_FORCE_TEMP))
     /* We need a new temporary; don't take this shortcut.  */;
   else if (same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (e)))
     {
-      if (same_type_p (type, TREE_TYPE (e)))
+      tree etype = TREE_TYPE (e);
+      if (same_type_p (type, etype))
        /* The call to fold will not always remove the NOP_EXPR as
           might be expected, since if one of the types is a typedef;
           the comparison in fold is just equality of pointers, not a
@@ -694,22 +742,29 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       /* For complex data types, we need to perform componentwise
         conversion.  */
       else if (TREE_CODE (type) == COMPLEX_TYPE)
-       return fold_if_not_in_template (convert_to_complex (type, e));
-      else if (TREE_CODE (type) == VECTOR_TYPE)
-       return fold_if_not_in_template (convert_to_vector (type, e));
+       return convert_to_complex_maybe_fold (type, e, dofold);
+      else if (VECTOR_TYPE_P (type))
+       return convert_to_vector (type, e);
       else if (TREE_CODE (e) == TARGET_EXPR)
        {
          /* Don't build a NOP_EXPR of class type.  Instead, change the
             type of the temporary.  */
+         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
          TREE_TYPE (e) = TREE_TYPE (TARGET_EXPR_SLOT (e)) = type;
          return e;
        }
+      else if (TREE_CODE (e) == CONSTRUCTOR)
+       {
+         gcc_assert (same_type_ignoring_top_level_qualifiers_p (type, etype));
+         TREE_TYPE (e) = type;
+         return e;
+       }
       else
        {
          /* We shouldn't be treating objects of ADDRESSABLE type as
             rvalues.  */
          gcc_assert (!TREE_ADDRESSABLE (type));
-         return fold_if_not_in_template (build_nop (type, e));
+         return build_nop (type, e);
        }
     }
 
@@ -750,9 +805,11 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
             the original value is within the range of the enumeration
             values. Otherwise, the resulting enumeration value is
             unspecified.  */
+         tree val = fold_for_warn (e);
          if ((complain & tf_warning)
-             && TREE_CODE (e) == INTEGER_CST
-             && !int_fits_type_p (e, ENUM_UNDERLYING_TYPE (type)))
+             && TREE_CODE (val) == INTEGER_CST
+             && ENUM_UNDERLYING_TYPE (type)
+             && !int_fits_type_p (val, ENUM_UNDERLYING_TYPE (type)))
            warning_at (loc, OPT_Wconversion, 
                        "the result of the conversion is unspecified because "
                        "%qE is outside the range of type %qT",
@@ -783,22 +840,24 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
             to the underlying type first.  */
          if (SCOPED_ENUM_P (intype) && (convtype & CONV_STATIC))
            e = build_nop (ENUM_UNDERLYING_TYPE (intype), e);
-         return cp_truthvalue_conversion (e);
+         if (complain & tf_warning)
+           return cp_truthvalue_conversion (e);
+         else
+           {
+             /* Prevent bogus -Wint-in-bool-context warnings coming
+                from c_common_truthvalue_conversion down the line.  */
+             warning_sentinel w (warn_int_in_bool_context);
+             return cp_truthvalue_conversion (e);
+           }
        }
 
-      converted = fold_if_not_in_template (convert_to_integer (type, e));
+      converted = convert_to_integer_maybe_fold (type, e, dofold);
 
       /* Ignore any integer overflow caused by the conversion.  */
       return ignore_overflows (converted, e);
     }
-  if (NULLPTR_TYPE_P (type) && e && null_ptr_cst_p (e))
-    {
-      if (complain & tf_warning)
-       maybe_warn_zero_as_null_pointer_constant (e, loc);
-      return nullptr_node;
-    }
-  if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
-    return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
+  if (INDIRECT_TYPE_P (type) || TYPE_PTRMEM_P (type))
+    return cp_convert_to_pointer (type, e, dofold, complain);
   if (code == VECTOR_TYPE)
     {
       tree in_vtype = TREE_TYPE (e);
@@ -813,7 +872,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
                      in_vtype, type);
          return error_mark_node;
        }
-      return fold_if_not_in_template (convert_to_vector (type, e));
+      return convert_to_vector (type, e);
     }
   if (code == REAL_TYPE || code == COMPLEX_TYPE)
     {
@@ -829,9 +888,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
                      TREE_TYPE (e));
        }
       if (code == REAL_TYPE)
-       return fold_if_not_in_template (convert_to_real (type, e));
+       return convert_to_real_maybe_fold (type, e, dofold);
       else if (code == COMPLEX_TYPE)
-       return fold_if_not_in_template (convert_to_complex (type, e));
+       return convert_to_complex_maybe_fold (type, e, dofold);
     }
 
   /* New C++ semantics:  since assignment is now based on
@@ -881,15 +940,139 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
     {
       /* If the conversion failed and expr was an invalid use of pointer to
         member function, try to report a meaningful error.  */
-      if (invalid_nonstatic_memfn_p (expr, complain))
+      if (invalid_nonstatic_memfn_p (loc, expr, complain))
        /* We displayed the error message.  */;
       else
-       error_at (loc, "conversion from %qT to non-scalar type %qT requested",
+       error_at (loc, "conversion from %qH to non-scalar type %qI requested",
                  TREE_TYPE (expr), type);
     }
   return error_mark_node;
 }
 
+/* If CALL is a call, return the callee; otherwise null.  */
+
+tree
+cp_get_callee (tree call)
+{
+  if (call == NULL_TREE)
+    return call;
+  else if (TREE_CODE (call) == CALL_EXPR)
+    return CALL_EXPR_FN (call);
+  else if (TREE_CODE (call) == AGGR_INIT_EXPR)
+    return AGGR_INIT_EXPR_FN (call);
+  return NULL_TREE;
+}
+
+/* FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL
+   if we can.  */
+
+tree
+cp_get_fndecl_from_callee (tree fn, bool fold /* = true */)
+{
+  if (fn == NULL_TREE)
+    return fn;
+  if (TREE_CODE (fn) == FUNCTION_DECL)
+    return fn;
+  tree type = TREE_TYPE (fn);
+  if (type == unknown_type_node)
+    return NULL_TREE;
+  gcc_assert (INDIRECT_TYPE_P (type));
+  if (fold)
+    fn = maybe_constant_init (fn);
+  STRIP_NOPS (fn);
+  if (TREE_CODE (fn) == ADDR_EXPR)
+    {
+      fn = TREE_OPERAND (fn, 0);
+      if (TREE_CODE (fn) == FUNCTION_DECL)
+       return fn;
+    }
+  return NULL_TREE;
+}
+
+/* Like get_callee_fndecl, but handles AGGR_INIT_EXPR as well and uses the
+   constexpr machinery.  */
+
+tree
+cp_get_callee_fndecl (tree call)
+{
+  return cp_get_fndecl_from_callee (cp_get_callee (call));
+}
+
+/* As above, but not using the constexpr machinery.  */
+
+tree
+cp_get_callee_fndecl_nofold (tree call)
+{
+  return cp_get_fndecl_from_callee (cp_get_callee (call), false);
+}
+
+/* Subroutine of convert_to_void.  Warn if we're discarding something with
+   attribute [[nodiscard]].  */
+
+static void
+maybe_warn_nodiscard (tree expr, impl_conv_void implicit)
+{
+  tree call = expr;
+  if (TREE_CODE (expr) == TARGET_EXPR)
+    call = TARGET_EXPR_INITIAL (expr);
+  location_t loc = cp_expr_loc_or_loc (call, input_location);
+  tree callee = cp_get_callee (call);
+  if (!callee)
+    return;
+
+  tree type = TREE_TYPE (callee);
+  if (TYPE_PTRMEMFUNC_P (type))
+    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+  if (INDIRECT_TYPE_P (type))
+    type = TREE_TYPE (type);
+
+  tree rettype = TREE_TYPE (type);
+  tree fn = cp_get_fndecl_from_callee (callee);
+  if (implicit != ICV_CAST && fn
+      && lookup_attribute ("nodiscard", DECL_ATTRIBUTES (fn)))
+    {
+      auto_diagnostic_group d;
+      if (warning_at (loc, OPT_Wunused_result,
+                     "ignoring return value of %qD, "
+                     "declared with attribute nodiscard", fn))
+       inform (DECL_SOURCE_LOCATION (fn), "declared here");
+    }
+  else if (implicit != ICV_CAST
+          && lookup_attribute ("nodiscard", TYPE_ATTRIBUTES (rettype)))
+    {
+      auto_diagnostic_group d;
+      if (warning_at (loc, OPT_Wunused_result,
+                     "ignoring returned value of type %qT, "
+                     "declared with attribute nodiscard", rettype))
+       {
+         if (fn)
+           inform (DECL_SOURCE_LOCATION (fn),
+                   "in call to %qD, declared here", fn);
+         inform (DECL_SOURCE_LOCATION (TYPE_NAME (rettype)),
+                 "%qT declared here", rettype);
+       }
+    }
+  else if (TREE_CODE (expr) == TARGET_EXPR
+          && lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (type)))
+    {
+      /* The TARGET_EXPR confuses do_warn_unused_result into thinking that the
+        result is used, so handle that case here.  */
+      if (fn)
+       {
+         auto_diagnostic_group d;
+         if (warning_at (loc, OPT_Wunused_result,
+                         "ignoring return value of %qD, "
+                         "declared with attribute warn_unused_result",
+                         fn))
+           inform (DECL_SOURCE_LOCATION (fn), "declared here");
+       }
+      else
+       warning_at (loc, OPT_Wunused_result,
+                   "ignoring return value of function "
+                   "declared with attribute warn_unused_result");
+    }
+}
+
 /* When an expression is used in a void context, its value is discarded and
    no lvalue-rvalue and similar conversions happen [expr.static.cast/4,
    stmt.expr/1, expr.comma/1].  This permits dereferencing an incomplete type
@@ -912,34 +1095,22 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
 tree
 convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
 {
-  location_t loc = EXPR_LOC_OR_HERE (expr);
+  location_t loc = cp_expr_loc_or_loc (expr, input_location);
 
   if (expr == error_mark_node
       || TREE_TYPE (expr) == error_mark_node)
     return error_mark_node;
 
+  expr = maybe_undo_parenthesized_ref (expr);
+
+  expr = mark_discarded_use (expr);
   if (implicit == ICV_CAST)
+    /* An explicit cast to void avoids all -Wunused-but-set* warnings.  */
     mark_exp_read (expr);
-  else
-    {
-      tree exprv = expr;
-
-      while (TREE_CODE (exprv) == COMPOUND_EXPR)
-       exprv = TREE_OPERAND (exprv, 1);
-      if (DECL_P (exprv)
-         || handled_component_p (exprv)
-         || INDIRECT_REF_P (exprv))
-       /* Expr is not being 'used' here, otherwise we whould have
-          called mark_{rl}value_use use here, which would have in turn
-          called mark_exp_read.  Rather, we call mark_exp_read directly
-          to avoid some warnings when
-          -Wunused-but-set-{variable,parameter} is in effect.  */
-       mark_exp_read (exprv);
-    }
 
   if (!TREE_TYPE (expr))
     return expr;
-  if (invalid_nonstatic_memfn_p (expr, complain))
+  if (invalid_nonstatic_memfn_p (loc, expr, complain))
     return error_mark_node;
   if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR)
     {
@@ -1004,13 +1175,23 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
       break;
 
     case CALL_EXPR:   /* We have a special meaning for volatile void fn().  */
+      /* cdtors may return this or void, depending on
+        targetm.cxx.cdtor_returns_this, but this shouldn't affect our
+        decisions here: neither nodiscard warnings (nodiscard cdtors
+        are nonsensical), nor should any constexpr or template
+        instantiations be affected by an ABI property that is, or at
+        least ought to be transparent to the language.  */
+      if (tree fn = cp_get_callee_fndecl_nofold (expr))
+       if (DECL_CONSTRUCTOR_P (fn) || DECL_DESTRUCTOR_P (fn))
+         return expr;
+
+      maybe_warn_nodiscard (expr, implicit);
       break;
 
     case INDIRECT_REF:
       {
        tree type = TREE_TYPE (expr);
-       int is_reference = TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0)))
-                          == REFERENCE_TYPE;
+       int is_reference = TYPE_REF_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
        int is_volatile = TYPE_VOLATILE (type);
        int is_complete = COMPLETE_TYPE_P (complete_type (type));
 
@@ -1160,6 +1341,8 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
                 && !is_reference)
               warning_at (loc, OPT_Wunused_value, "value computed is not used");
             expr = TREE_OPERAND (expr, 0);
+           if (TREE_CODE (expr) == CALL_EXPR)
+             maybe_warn_nodiscard (expr, implicit);
           }
 
        break;
@@ -1216,11 +1399,12 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
 
     case TARGET_EXPR:
       /* Don't bother with the temporary object returned from a function if
-        we don't use it and don't need to destroy it.  We'll still
+        we don't use it, don't need to destroy it, and won't abort in
+        assign_temp.  We'll still
         allocate space for it in expand_call or declare_return_variable,
         but we don't need to track it through all the tree phases.  */
       if (TARGET_EXPR_IMPLICIT_P (expr)
-         && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (expr)))
+         && !TREE_ADDRESSABLE (TREE_TYPE (expr)))
        {
          tree init = TARGET_EXPR_INITIAL (expr);
          if (TREE_CODE (init) == AGGR_INIT_EXPR
@@ -1228,17 +1412,19 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
            {
              tree fn = AGGR_INIT_EXPR_FN (init);
              expr = build_call_array_loc (input_location,
-                                          TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))),
+                                          TREE_TYPE (TREE_TYPE
+                                                     (TREE_TYPE (fn))),
                                           fn,
                                           aggr_init_expr_nargs (init),
                                           AGGR_INIT_EXPR_ARGP (init));
            }
        }
+      maybe_warn_nodiscard (expr, implicit);
       break;
 
     default:;
     }
-  expr = resolve_nondeduced_context (expr);
+  expr = resolve_nondeduced_context (expr, complain);
   {
     tree probe = expr;
 
@@ -1282,7 +1468,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
            }
        else
          return error_mark_node;
-       expr = void_zero_node;
+       expr = void_node;
       }
     else if (implicit != ICV_CAST && probe == expr && is_overloaded_fn (probe))
       {
@@ -1402,7 +1588,9 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
                            || code == PREDECREMENT_EXPR
                            || code == PREINCREMENT_EXPR
                            || code == POSTDECREMENT_EXPR
-                           || code == POSTINCREMENT_EXPR)))
+                           || code == POSTINCREMENT_EXPR))
+                  || code == VEC_PERM_EXPR
+                  || code == VEC_COND_EXPR)
                   && (complain & tf_warning))
                warning_at (loc, OPT_Wunused_value, "value computed is not used");
            }
@@ -1410,7 +1598,7 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
       expr = build1 (CONVERT_EXPR, void_type_node, expr);
     }
   if (! TREE_SIDE_EFFECTS (expr))
-    expr = void_zero_node;
+    expr = void_node;
   return expr;
 }
 
@@ -1441,10 +1629,10 @@ convert (tree type, tree expr)
 
   intype = TREE_TYPE (expr);
 
-  if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
-    return fold_if_not_in_template (build_nop (type, expr));
+  if (INDIRECT_TYPE_P (type) && INDIRECT_TYPE_P (intype))
+    return build_nop (type, expr);
 
-  return ocp_convert (type, expr, CONV_OLD_CONVERT,
+  return ocp_convert (type, expr, CONV_BACKEND_CONVERT,
                      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
                      tf_warning_or_error);
 }
@@ -1460,13 +1648,11 @@ convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
   enum tree_code code = TREE_CODE (type);
 
   if (code == REFERENCE_TYPE)
-    return (fold_if_not_in_template
-           (convert_to_reference (type, e, CONV_C_CAST, 0,
-                                  NULL_TREE, complain)));
+    return convert_to_reference (type, e, CONV_C_CAST, 0,
+                                NULL_TREE, complain);
 
   if (code == POINTER_TYPE)
-    return fold_if_not_in_template (convert_to_pointer_force (type, e,
-                                                             complain));
+    return convert_to_pointer_force (type, e, complain);
 
   /* From typeck.c convert_for_assignment */
   if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
@@ -1513,11 +1699,11 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
   tree conv = NULL_TREE;
   tree winner = NULL_TREE;
 
-  if (expr == null_node
+  if (null_node_p (expr)
       && (desires & WANT_INT)
       && !(desires & WANT_NULL))
     {
-      source_location loc =
+      location_t loc =
        expansion_point_location_if_in_system_header (input_location);
 
       warning_at (loc, OPT_Wconversion_null,
@@ -1533,7 +1719,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       case INTEGER_TYPE:
        if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
          return expr;
-       /* else fall through...  */
+       /* fall through.  */
 
       case BOOLEAN_TYPE:
        return (desires & WANT_INT) ? expr : NULL_TREE;
@@ -1583,7 +1769,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       int win = 0;
       tree candidate;
       tree cand = TREE_VALUE (conv);
-      cand = OVL_CURRENT (cand);
+      cand = OVL_FIRST (cand);
 
       if (winner && winner == cand)
        continue;
@@ -1653,8 +1839,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
                    {
                      error ("ambiguous default type conversion from %qT",
                             basetype);
-                     error ("  candidate conversions include %qD and %qD",
-                            winner, cand);
+                     inform (input_location,
+                             "  candidate conversions include %qD and %qD",
+                             winner, cand);
                    }
                  return error_mark_node;
                }
@@ -1696,31 +1883,53 @@ type_promotes_to (tree type)
   if (TREE_CODE (type) == BOOLEAN_TYPE)
     type = integer_type_node;
 
-  /* Scoped enums don't promote, but pretend they do for backward ABI bug
-     compatibility wrt varargs.  */
-  else if (SCOPED_ENUM_P (type) && abi_version_at_least (6))
-    ;
-
   /* Normally convert enums to int, but convert wide enums to something
-     wider.  */
+     wider.  Scoped enums don't promote, but pretend they do for backward
+     ABI bug compatibility wrt varargs.  */
   else if (TREE_CODE (type) == ENUMERAL_TYPE
+          || type == char8_type_node
           || type == char16_type_node
           || type == char32_type_node
           || type == wchar_type_node)
     {
+      tree prom = type;
+
+      if (TREE_CODE (type) == ENUMERAL_TYPE)
+       {
+         prom = ENUM_UNDERLYING_TYPE (prom);
+         if (!ENUM_IS_SCOPED (type)
+             && ENUM_FIXED_UNDERLYING_TYPE_P (type))
+           {
+             /* ISO C++17, 7.6/4.  A prvalue of an unscoped enumeration type
+                whose underlying type is fixed (10.2) can be converted to a
+                prvalue of its underlying type. Moreover, if integral promotion
+                can be applied to its underlying type, a prvalue of an unscoped
+                enumeration type whose underlying type is fixed can also be 
+                converted to a prvalue of the promoted underlying type.  */
+             return type_promotes_to (prom);
+           }
+       }
+
       int precision = MAX (TYPE_PRECISION (type),
                           TYPE_PRECISION (integer_type_node));
       tree totype = c_common_type_for_size (precision, 0);
+      if (TYPE_UNSIGNED (prom)
+         && ! int_fits_type_p (TYPE_MAX_VALUE (prom), totype))
+       prom = c_common_type_for_size (precision, 1);
+      else
+       prom = totype;
       if (SCOPED_ENUM_P (type))
-       warning (OPT_Wabi, "scoped enum %qT will not promote to an integral "
-                "type in a future version of GCC", type);
-      if (TREE_CODE (type) == ENUMERAL_TYPE)
-       type = ENUM_UNDERLYING_TYPE (type);
-      if (TYPE_UNSIGNED (type)
-         && ! int_fits_type_p (TYPE_MAX_VALUE (type), totype))
-       type = c_common_type_for_size (precision, 1);
+       {
+         if (abi_version_crosses (6)
+             && TYPE_MODE (prom) != TYPE_MODE (type))
+           warning (OPT_Wabi, "scoped enum %qT passed through ... as "
+                    "%qT before %<-fabi-version=6%>, %qT after",
+                    type, prom, ENUM_UNDERLYING_TYPE (type));
+         if (!abi_version_at_least (6))
+           type = prom;
+       }
       else
-       type = totype;
+       type = prom;
     }
   else if (c_promoting_integer_type_p (type))
     {
@@ -1742,9 +1951,30 @@ type_promotes_to (tree type)
    closely.  Although they are used only in pt.c at the moment, they
    should presumably be used everywhere in the future.  */
 
+/* True iff EXPR can be converted to TYPE via a qualification conversion.
+   Callers should check for identical types before calling this function.  */
+
+bool
+can_convert_qual (tree type, tree expr)
+{
+  tree expr_type = TREE_TYPE (expr);
+  gcc_assert (!same_type_p (type, expr_type));
+
+  if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type))
+    return comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type));
+  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type))
+    return (same_type_p (TYPE_PTRMEM_CLASS_TYPE (type),
+                        TYPE_PTRMEM_CLASS_TYPE (expr_type))
+           && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type),
+                               TYPE_PTRMEM_POINTED_TO_TYPE (expr_type)));
+  else
+    return false;
+}
+
 /* Attempt to perform qualification conversions on EXPR to convert it
    to TYPE.  Return the resulting expression, or error_mark_node if
-   the conversion was impossible.  */
+   the conversion was impossible.  Since this is only used by
+   convert_nontype_argument, we fold the conversion.  */
 
 tree
 perform_qualification_conversions (tree type, tree expr)
@@ -1755,15 +1985,119 @@ perform_qualification_conversions (tree type, tree expr)
 
   if (same_type_p (type, expr_type))
     return expr;
-  else if (TYPE_PTR_P (type) && TYPE_PTR_P (expr_type)
-          && comp_ptr_ttypes (TREE_TYPE (type), TREE_TYPE (expr_type)))
-    return build_nop (type, expr);
-  else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (expr_type)
-          && same_type_p (TYPE_PTRMEM_CLASS_TYPE (type),
-                          TYPE_PTRMEM_CLASS_TYPE (expr_type))
-          && comp_ptr_ttypes (TYPE_PTRMEM_POINTED_TO_TYPE (type),
-                              TYPE_PTRMEM_POINTED_TO_TYPE (expr_type)))
-    return build_nop (type, expr);
+  else if (can_convert_qual (type, expr))
+    return cp_fold_convert (type, expr);
   else
     return error_mark_node;
 }
+
+/* True iff T is a transaction-safe function type.  */
+
+bool
+tx_safe_fn_type_p (tree t)
+{
+  if (TREE_CODE (t) != FUNCTION_TYPE
+      && TREE_CODE (t) != METHOD_TYPE)
+    return false;
+  return !!lookup_attribute ("transaction_safe", TYPE_ATTRIBUTES (t));
+}
+
+/* Return the transaction-unsafe variant of transaction-safe function type
+   T.  */
+
+tree
+tx_unsafe_fn_variant (tree t)
+{
+  gcc_assert (tx_safe_fn_type_p (t));
+  tree attrs = remove_attribute ("transaction_safe",
+                                TYPE_ATTRIBUTES (t));
+  return cp_build_type_attribute_variant (t, attrs);
+}
+
+/* Return true iff FROM can convert to TO by a transaction-safety
+   conversion.  */
+
+static bool
+can_convert_tx_safety (tree to, tree from)
+{
+  return (flag_tm && tx_safe_fn_type_p (from)
+         && same_type_p (to, tx_unsafe_fn_variant (from)));
+}
+
+/* Return true iff FROM can convert to TO by dropping noexcept.  */
+
+static bool
+noexcept_conv_p (tree to, tree from)
+{
+  if (!flag_noexcept_type)
+    return false;
+
+  tree t = non_reference (to);
+  tree f = from;
+  if (TYPE_PTRMEMFUNC_P (t)
+      && TYPE_PTRMEMFUNC_P (f))
+    {
+      t = TYPE_PTRMEMFUNC_FN_TYPE (t);
+      f = TYPE_PTRMEMFUNC_FN_TYPE (f);
+    }
+  if (TYPE_PTR_P (t)
+      && TYPE_PTR_P (f))
+    {
+      t = TREE_TYPE (t);
+      f = TREE_TYPE (f);
+    }
+  tree_code code = TREE_CODE (f);
+  if (TREE_CODE (t) != code)
+    return false;
+  if (code != FUNCTION_TYPE && code != METHOD_TYPE)
+    return false;
+  if (!type_throw_all_p (t)
+      || type_throw_all_p (f))
+    return false;
+  tree v = build_exception_variant (f, NULL_TREE);
+  return same_type_p (t, v);
+}
+
+/* Return true iff FROM can convert to TO by a function pointer conversion.  */
+
+bool
+fnptr_conv_p (tree to, tree from)
+{
+  tree t = non_reference (to);
+  tree f = from;
+  if (TYPE_PTRMEMFUNC_P (t)
+      && TYPE_PTRMEMFUNC_P (f))
+    {
+      t = TYPE_PTRMEMFUNC_FN_TYPE (t);
+      f = TYPE_PTRMEMFUNC_FN_TYPE (f);
+    }
+  if (TYPE_PTR_P (t)
+      && TYPE_PTR_P (f))
+    {
+      t = TREE_TYPE (t);
+      f = TREE_TYPE (f);
+    }
+
+  return (noexcept_conv_p (t, f)
+         || can_convert_tx_safety (t, f));
+}
+
+/* Return FN with any NOP_EXPRs stripped that represent function pointer
+   conversions or conversions to the same type.  */
+
+tree
+strip_fnptr_conv (tree fn)
+{
+  while (TREE_CODE (fn) == NOP_EXPR)
+    {
+      tree op = TREE_OPERAND (fn, 0);
+      tree ft = TREE_TYPE (fn);
+      tree ot = TREE_TYPE (op);
+      if (same_type_p (ft, ot)
+         || fnptr_conv_p (ft, ot))
+       fn = op;
+      else
+       break;
+    }
+  return fn;
+}