decl.c (cxx_maybe_build_cleanup): When clearing location of cleanup...
[gcc.git] / gcc / cp / decl.c
index e0d67328121e9c57a0171461c156f80289dde230..5e510c91aa30c0c35afe49669a60895203f0719c 100644 (file)
@@ -920,6 +920,31 @@ determine_local_discriminator (tree decl)
 }
 
 \f
+
+/* Returns true if functions FN1 and FN2 have equivalent trailing
+   requires clauses.  */
+
+static bool
+function_requirements_equivalent_p (tree newfn, tree oldfn)
+{
+  /* In the concepts TS, the combined constraints are compared.  */
+  if (cxx_dialect < cxx2a)
+    {
+      tree ci1 = get_constraints (oldfn);
+      tree ci2 = get_constraints (newfn);
+      tree req1 = ci1 ? CI_ASSOCIATED_CONSTRAINTS (ci1) : NULL_TREE;
+      tree req2 = ci2 ? CI_ASSOCIATED_CONSTRAINTS (ci2) : NULL_TREE;
+      return cp_tree_equal (req1, req2);
+    }
+
+  /* Compare only trailing requirements.  */
+  tree reqs1 = get_trailing_function_requirements (newfn);
+  tree reqs2 = get_trailing_function_requirements (oldfn);
+  if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE))
+    return false;
+  return cp_tree_equal (reqs1, reqs2);
+}
+
 /* Subroutine of duplicate_decls: return truthvalue of whether
    or not types of these decls match.
 
@@ -999,6 +1024,12 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
       else
        types_match = 0;
 
+      /* Two function declarations match if either has a requires-clause
+         then both have a requires-clause and their constraints-expressions
+         are equivalent.  */
+      if (types_match && flag_concepts)
+       types_match = function_requirements_equivalent_p (newdecl, olddecl);
+
       /* The decls dont match if they correspond to two different versions
         of the same function.   Disallow extern "C" functions to be
         versions for now.  */
@@ -1013,23 +1044,21 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
     }
   else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
     {
+      if (!template_heads_equivalent_p (newdecl, olddecl))
+       return 0;
+
       tree oldres = DECL_TEMPLATE_RESULT (olddecl);
       tree newres = DECL_TEMPLATE_RESULT (newdecl);
 
       if (TREE_CODE (newres) != TREE_CODE (oldres))
        return 0;
 
-      if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
-                               DECL_TEMPLATE_PARMS (olddecl)))
-       return 0;
-
-      if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
-       types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
-                      && equivalently_constrained (olddecl, newdecl));
+      /* Two template types match if they are the same. Otherwise, compare
+         the underlying declarations.  */
+      if (TREE_CODE (newres) == TYPE_DECL)
+        types_match = same_type_p (TREE_TYPE (newres), TREE_TYPE (oldres));
       else
-       // We don't need to check equivalently_constrained for variable and
-       // function templates because we check it on the results.
-       types_match = decls_match (oldres, newres);
+       types_match = decls_match (newres, oldres);
     }
   else
     {
@@ -1057,11 +1086,6 @@ decls_match (tree newdecl, tree olddecl, bool record_versions /* = true */)
                                 COMPARE_REDECLARATION);
     }
 
-  // Normal functions can be constrained, as can variable partial
-  // specializations.
-  if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl))
-    types_match = equivalently_constrained (newdecl, olddecl);
-
   return types_match;
 }
 
@@ -1336,6 +1360,46 @@ merge_attribute_bits (tree newdecl, tree olddecl)
                          && lookup_attribute ("gnu_inline",            \
                                               DECL_ATTRIBUTES (fn)))
 
+/* A subroutine of duplicate_decls. Emits a diagnostic when newdecl
+   ambiguates olddecl.  Returns true if an error occurs.  */
+
+static bool
+duplicate_function_template_decls (tree newdecl, tree olddecl)
+{
+
+  tree newres = DECL_TEMPLATE_RESULT (newdecl);
+  tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+  /* Function template declarations can be differentiated by parameter
+     and return type.  */
+  if (compparms (TYPE_ARG_TYPES (TREE_TYPE (oldres)),
+                TYPE_ARG_TYPES (TREE_TYPE (newres)))
+       && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
+                      TREE_TYPE (TREE_TYPE (olddecl))))
+    {
+      /* ... and also by their template-heads and requires-clauses.  */
+      if (template_heads_equivalent_p (newdecl, olddecl)
+         && function_requirements_equivalent_p (newres, oldres))
+       {
+         error ("ambiguating new declaration %q+#D", newdecl);
+         inform (DECL_SOURCE_LOCATION (olddecl),
+                 "old declaration %q#D", olddecl);
+         return true;
+       }
+
+      /* FIXME: The types are the same but the are differences
+        in either the template heads or function requirements.
+        We should be able to diagnose a set of common errors
+        stemming from these declarations. For example:
+
+          template<typename T> requires C void f(...);
+          template<typename T> void f(...) requires C;
+
+        These are functionally equivalent but not equivalent.  */
+    }
+
+  return false;
+}
+
 /* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
    If the redeclaration is invalid, a diagnostic is issued, and the
    error_mark_node is returned.  Otherwise, OLDDECL is returned.
@@ -1644,11 +1708,14 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
 
       if (TREE_CODE (newdecl) == TEMPLATE_DECL)
        {
+         tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+         tree newres = DECL_TEMPLATE_RESULT (newdecl);
+
          /* The name of a class template may not be declared to refer to
             any other template, class, function, object, namespace, value,
             or type in the same scope.  */
-         if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL
-             || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
+         if (TREE_CODE (oldres) == TYPE_DECL
+             || TREE_CODE (newres) == TYPE_DECL)
            {
              error_at (newdecl_loc,
                        "conflicting declaration of template %q#D", newdecl);
@@ -1656,24 +1723,13 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
                      "previous declaration %q#D", olddecl);
              return error_mark_node;
            }
-         else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
-                  && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
-                  && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
-                                TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))))
-                  && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
-                                          DECL_TEMPLATE_PARMS (olddecl))
-                  /* Template functions can be disambiguated by
-                     return type.  */
-                  && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
-                                  TREE_TYPE (TREE_TYPE (olddecl)))
-                   /* Template functions can also be disambiguated by
-                     constraints.  */
-                   && equivalently_constrained (olddecl, newdecl))
+
+         else if (TREE_CODE (oldres) == FUNCTION_DECL
+                  && TREE_CODE (newres) == FUNCTION_DECL)
            {
-             error_at (newdecl_loc, "ambiguating new declaration %q#D",
-                       newdecl);
-             inform (olddecl_loc,
-                     "old declaration %q#D", olddecl);
+             if (duplicate_function_template_decls (newdecl, olddecl))
+               return error_mark_node;
+             return NULL_TREE;
            }
           else if (check_concept_refinement (olddecl, newdecl))
            return error_mark_node;
@@ -2916,6 +2972,9 @@ redeclaration_error_message (tree newdecl, tree olddecl)
          return NULL;
        }
 
+      if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == CONCEPT_DECL)
+        return G_("redefinition of %q#D");
+
       if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL
          || (DECL_TEMPLATE_RESULT (newdecl)
              == DECL_TEMPLATE_RESULT (olddecl)))
@@ -4146,6 +4205,9 @@ initialize_predefined_identifiers (void)
     {"value", &value_identifier, cik_normal},
     {"_FUN", &fun_identifier, cik_normal},
     {"__closure", &closure_identifier, cik_normal},
+    {"heap uninit", &heap_uninit_identifier, cik_normal},
+    {"heap ", &heap_identifier, cik_normal},
+    {"heap deleted", &heap_deleted_identifier, cik_normal},
     {NULL, NULL, cik_normal}
   };
 
@@ -4928,9 +4990,9 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
       /* Anonymous unions are objects, so they can have specifiers.  */;
       SET_ANON_AGGR_TYPE_P (declared_type);
 
-      if (TREE_CODE (declared_type) != UNION_TYPE
-         && !in_system_header_at (input_location))
-       pedwarn (input_location, OPT_Wpedantic, "ISO C++ prohibits anonymous structs");
+      if (TREE_CODE (declared_type) != UNION_TYPE)
+       pedwarn (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (declared_type)),
+                OPT_Wpedantic, "ISO C++ prohibits anonymous structs");
     }
 
   else
@@ -7006,6 +7068,19 @@ notice_forced_label_r (tree *tp, int *walk_subtrees, void *)
   return NULL_TREE;
 }
 
+/* Return true if DECL has either a trivial destructor, or for C++2A
+   is constexpr and has a constexpr destructor.  */
+
+static bool
+decl_maybe_constant_destruction (tree decl, tree type)
+{
+  return (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
+         || (cxx_dialect >= cxx2a
+             && VAR_P (decl)
+             && DECL_DECLARED_CONSTEXPR_P (decl)
+             && type_has_constexpr_destructor (strip_array_types (type))));
+}
+
 /* Finish processing of a declaration;
    install its line number and initial value.
    If the length of an array type is not known before,
@@ -7430,7 +7505,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
            TREE_READONLY (decl) = 1;
 
          /* Likewise if it needs destruction.  */
-         if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+         if (!decl_maybe_constant_destruction (decl, type))
            TREE_READONLY (decl) = 0;
        }
 
@@ -7704,13 +7779,6 @@ get_tuple_decomp_init (tree decl, unsigned i)
    based on the actual type of the variable, so store it in a hash table.  */
 
 static GTY((cache)) tree_cache_map *decomp_type_table;
-static void
-store_decomp_type (tree v, tree t)
-{
-  if (!decomp_type_table)
-    decomp_type_table = tree_cache_map::create_ggc (13);
-  decomp_type_table->put (v, t);
-}
 
 tree
 lookup_decomp_type (tree v)
@@ -7946,7 +8014,7 @@ cp_finish_decomp (tree decl, tree first, unsigned int count)
              goto error_out;
            }
          /* Save the decltype away before reference collapse.  */
-         store_decomp_type (v[i], eltype);
+         hash_map_safe_put<hm_ggc> (decomp_type_table, v[i], eltype);
          eltype = cp_build_reference_type (eltype, !lvalue_p (init));
          TREE_TYPE (v[i]) = eltype;
          layout_decl (v[i], 0);
@@ -8319,6 +8387,13 @@ register_dtor_fn (tree decl)
   if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
     return void_node;
 
+  if (decl_maybe_constant_destruction (decl, type)
+      && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+    {
+      cxx_maybe_build_cleanup (decl, tf_warning_or_error);
+      return void_node;
+    }
+
   /* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or
      "__aeabi_atexit"), and DECL is a class object, we can just pass the
      destructor to "__cxa_atexit"; we don't have to build a temporary
@@ -8436,7 +8511,7 @@ expand_static_init (tree decl, tree init)
   gcc_assert (TREE_STATIC (decl));
 
   /* Some variables require no dynamic initialization.  */
-  if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
+  if (decl_maybe_constant_destruction (decl, TREE_TYPE (decl)))
     {
       /* Make sure the destructor is callable.  */
       cxx_maybe_build_cleanup (decl, tf_warning_or_error);
@@ -8969,12 +9044,12 @@ grokfndecl (tree ctype,
       tree tmpl_reqs = NULL_TREE;
       if (processing_template_decl > template_class_depth (ctype))
         tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
-
-      /* Adjust the required expression into a constraint. */
-      if (decl_reqs)
-        decl_reqs = normalize_expression (decl_reqs);
-
       tree ci = build_constraints (tmpl_reqs, decl_reqs);
+      if (concept_p && ci)
+        {
+          error_at (location, "a function concept cannot be constrained");
+          ci = NULL_TREE;
+        }
       set_constraints (decl, ci);
     }
 
@@ -9614,12 +9689,18 @@ grokvardecl (tree type,
       if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node))
        error_at (declspecs->locations[ds_type_spec],
                  "concept must have type %<bool%>");
+      if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
+        {
+          error_at (location, "a variable concept cannot be constrained");
+          TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
+        }
     }
   else if (flag_concepts
           && processing_template_decl > template_class_depth (scope))
     {
       tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
       tree ci = build_constraints (reqs, NULL_TREE);
+
       set_constraints (decl, ci);
     }
 
@@ -9665,10 +9746,12 @@ build_ptrmemfunc_type (tree type)
   TYPE_PTRMEMFUNC_FLAG (t) = 1;
 
   field = build_decl (input_location, FIELD_DECL, pfn_identifier, type);
+  DECL_NONADDRESSABLE_P (field) = 1;
   fields = field;
 
   field = build_decl (input_location, FIELD_DECL, delta_identifier, 
                      delta_type_node);
+  DECL_NONADDRESSABLE_P (field) = 1;
   DECL_CHAIN (field) = fields;
   fields = field;
 
@@ -10523,7 +10606,6 @@ grokdeclarator (const cp_declarator *declarator,
   bool constinit_p = decl_spec_seq_has_spec_p (declspecs, ds_constinit);
   bool late_return_type_p = false;
   bool array_parameter_p = false;
-  location_t saved_loc = input_location;
   tree reqs = NULL_TREE;
 
   signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
@@ -10948,14 +11030,15 @@ grokdeclarator (const cp_declarator *declarator,
     {
       if (! int_n_enabled_p[declspecs->int_n_idx])
        {
-         error ("%<__int%d%> is not supported by this target",
-                int_n_data[declspecs->int_n_idx].bitsize);
+         error_at (declspecs->locations[ds_type_spec],
+                   "%<__int%d%> is not supported by this target",
+                   int_n_data[declspecs->int_n_idx].bitsize);
          explicit_intN = false;
        }
       /* Don't pedwarn if the alternate "__intN__" form has been used instead
         of "__intN".  */
       else if (!int_n_alt && pedantic && ! in_system_header_at (input_location))
-       pedwarn (input_location, OPT_Wpedantic,
+       pedwarn (declspecs->locations[ds_type_spec], OPT_Wpedantic,
                 "ISO C++ does not support %<__int%d%> for %qs",
                 int_n_data[declspecs->int_n_idx].bitsize, name);
     }
@@ -11330,7 +11413,10 @@ grokdeclarator (const cp_declarator *declarator,
           && storage_class != sc_static)
          || typedef_p))
     {
-      error ("multiple storage classes in declaration of %qs", name);
+      location_t loc
+       = min_location (declspecs->locations[ds_thread],
+                       declspecs->locations[ds_storage_class]);
+      error_at (loc, "multiple storage classes in declaration of %qs", name);
       thread_p = false;
     }
   if (decl_context != NORMAL
@@ -11489,7 +11575,9 @@ grokdeclarator (const cp_declarator *declarator,
          type = create_array_type_for_decl (dname, type,
                                             declarator->u.array.bounds,
                                             declarator->id_loc);
-         if (!valid_array_size_p (input_location, type, dname))
+         if (!valid_array_size_p (dname
+                                  ? declarator->id_loc : input_location,
+                                  type, dname))
            type = error_mark_node;
 
          if (declarator->std_attributes)
@@ -11508,9 +11596,10 @@ grokdeclarator (const cp_declarator *declarator,
 
            /* Declaring a function type.  */
 
-           input_location = declspecs->locations[ds_type_spec];
-           abstract_virtuals_error (ACU_RETURN, type);
-           input_location = saved_loc;
+           {
+             iloc_sentinel ils (declspecs->locations[ds_type_spec]);
+             abstract_virtuals_error (ACU_RETURN, type);
+           }
 
            /* Pick up type qualifiers which should be applied to `this'.  */
            memfn_quals = declarator->u.function.qualifiers;
@@ -12519,12 +12608,18 @@ grokdeclarator (const cp_declarator *declarator,
       if (ctype || in_namespace)
        error ("cannot use %<::%> in parameter declaration");
 
-      if (type_uses_auto (type)
-         && !(cxx_dialect >= cxx17 && template_parm_flag))
+      tree auto_node = type_uses_auto (type);
+      if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
        {
          if (cxx_dialect >= cxx14)
-           error_at (typespec_loc,
-                     "%<auto%> parameter not permitted in this context");
+           {
+             if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
+               error_at (typespec_loc,
+                         "cannot declare a parameter with %<decltype(auto)%>");
+             else
+               error_at (typespec_loc,
+                         "%<auto%> parameter not permitted in this context");
+           }
          else
            error_at (typespec_loc, "parameter declared %<auto%>");
          type = error_mark_node;
@@ -12696,12 +12791,13 @@ grokdeclarator (const cp_declarator *declarator,
                              "a destructor cannot be %<concept%>");
                     return error_mark_node;
                   }
-                if (constexpr_p)
-                  {
-                    error_at (declspecs->locations[ds_constexpr],
-                             "a destructor cannot be %<constexpr%>");
-                    return error_mark_node;
-                  }
+               if (constexpr_p && cxx_dialect < cxx2a)
+                 {
+                   error_at (declspecs->locations[ds_constexpr],
+                             "%<constexpr%> destructors only available"
+                             " with %<-std=c++2a%> or %<-std=gnu++2a%>");
+                   return error_mark_node;
+                 }
              }
            else if (sfk == sfk_constructor && friendp && !ctype)
              {
@@ -12729,8 +12825,8 @@ grokdeclarator (const cp_declarator *declarator,
                tree tmpl = TREE_OPERAND (unqualified_id, 0);
                if (variable_template_p (tmpl))
                  {
-                   error ("specialization of variable template %qD "
-                          "declared as function", tmpl);
+                   error_at (id_loc, "specialization of variable template "
+                             "%qD declared as function", tmpl);
                    inform (DECL_SOURCE_LOCATION (tmpl),
                            "variable template declared here");
                    return error_mark_node;
@@ -12738,10 +12834,11 @@ grokdeclarator (const cp_declarator *declarator,
              }
 
            /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node.  */
-           function_context = (ctype != NULL_TREE) ?
-             decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
-           publicp = (! friendp || ! staticp)
-             && function_context == NULL_TREE;
+           function_context
+             = (ctype != NULL_TREE
+                ? decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE);
+           publicp = ((! friendp || ! staticp)
+                      && function_context == NULL_TREE);
 
            decl = grokfndecl (ctype, type,
                               TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
@@ -13712,7 +13809,8 @@ grok_ctor_properties (const_tree ctype, const_tree decl)
         or implicitly defined), there's no need to worry about their
         existence.  Theoretically, they should never even be
         instantiated, but that's hard to forestall.  */
-      error ("invalid constructor; you probably meant %<%T (const %T&)%>",
+      error_at (DECL_SOURCE_LOCATION (decl),
+               "invalid constructor; you probably meant %<%T (const %T&)%>",
                ctype, ctype);
       return false;
     }
@@ -15055,11 +15153,8 @@ finish_enum_value_list (tree enumtype)
      type of the enumeration.  */
   for (values = TYPE_VALUES (enumtype); values; values = TREE_CHAIN (values))
     {
-      location_t saved_location;
-
       decl = TREE_VALUE (values);
-      saved_location = input_location;
-      input_location = DECL_SOURCE_LOCATION (decl);
+      iloc_sentinel ils (DECL_SOURCE_LOCATION (decl));
       if (fixed_underlying_type_p)
         /* If the enumeration type has a fixed underlying type, we
            already checked all of the enumerator values.  */
@@ -15068,8 +15163,6 @@ finish_enum_value_list (tree enumtype)
         value = perform_implicit_conversion (underlying_type,
                                              DECL_INITIAL (decl),
                                              tf_warning_or_error);
-      input_location = saved_location;
-
       /* Do not clobber shared ints.  */
       if (value != error_mark_node)
        {
@@ -16340,8 +16433,17 @@ finish_function (bool inline_p)
   if (!processing_template_decl && FNDECL_USED_AUTO (fndecl)
       && TREE_TYPE (fntype) == DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
     {
-      if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl)))
+      if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
+          && !current_function_returns_value
+          && !current_function_returns_null)
        {
+         /* We haven't applied return type deduction because we haven't
+             seen any return statements. Do that now.  */
+         tree node = type_uses_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl));
+         do_auto_deduction (DECL_SAVED_AUTO_RETURN_TYPE (fndecl),
+                            void_node, node, tf_warning_or_error,
+                             adc_return_type);
+
          apply_deduced_return_type (fndecl, void_type_node);
          fntype = TREE_TYPE (fndecl);
        }
@@ -16746,6 +16848,9 @@ cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
        cleanup = error_mark_node;
       else if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
        /* Discard the call.  */;
+      else if (decl_maybe_constant_destruction (decl, type)
+              && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+       cxx_constant_dtor (call, decl);
       else if (cleanup)
        cleanup = cp_build_compound_expr (cleanup, call, complain);
       else
@@ -16759,6 +16864,8 @@ cxx_maybe_build_cleanup (tree decl, tsubst_flags_t complain)
      the end of the block.  So let's unset the location of the
      destructor call instead.  */
   protected_set_expr_location (cleanup, UNKNOWN_LOCATION);
+  if (cleanup && CONVERT_EXPR_P (cleanup))
+    protected_set_expr_location (TREE_OPERAND (cleanup, 0), UNKNOWN_LOCATION);
 
   if (cleanup
       && DECL_P (decl)
@@ -16928,7 +17035,9 @@ require_deduced_type (tree decl, tsubst_flags_t complain)
 {
   if (undeduced_auto_decl (decl))
     {
-      if (complain & tf_error)
+      if (TREE_NO_WARNING (decl) && seen_error ())
+       /* We probably already complained about deduction failure.  */;
+      else if (complain & tf_error)
        error ("use of %qD before deduction of %<auto%>", decl);
       return false;
     }