]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/cp/pt.c
PR c++/90138
[thirdparty/gcc.git] / gcc / cp / pt.c
index 7dc6e44cf7be99999ce1c6fec7592b23f98b99a9..842dacf95431c638a149afcd2f0d2ecf0989cb5d 100644 (file)
@@ -1090,7 +1090,8 @@ maybe_process_partial_specialization (tree type)
                  type_specializations->remove_elt (&elt);
 
                  elt.tmpl = tmpl;
-                 elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
+                 CLASSTYPE_TI_ARGS (inst)
+                   = elt.args = INNERMOST_TEMPLATE_ARGS (elt.args);
 
                  spec_entry **slot
                    = type_specializations->find_slot (&elt, INSERT);
@@ -1861,6 +1862,23 @@ iterative_hash_template_arg (tree arg, hashval_t val)
       /* Now hash operands as usual.  */
       break;
 
+    case CALL_EXPR:
+      {
+       tree fn = CALL_EXPR_FN (arg);
+       if (tree name = dependent_name (fn))
+         {
+           if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+             val = iterative_hash_template_arg (TREE_OPERAND (fn, 1), val);
+           fn = name;
+         }
+       val = iterative_hash_template_arg (fn, val);
+       call_expr_arg_iterator ai;
+       for (tree x = first_call_expr_arg (arg, &ai); x;
+            x = next_call_expr_arg (&ai))
+         val = iterative_hash_template_arg (x, val);
+       return val;
+      }
+
     default:
       break;
     }
@@ -3915,7 +3933,7 @@ make_pack_expansion (tree arg, tsubst_flags_t complain)
          class expansion.  */
       ppd.visited = new hash_set<tree>;
       ppd.parameter_packs = &parameter_packs;
-      ppd.type_pack_expansion_p = true;
+      ppd.type_pack_expansion_p = false;
       gcc_assert (TYPE_P (TREE_PURPOSE (arg)));
       cp_walk_tree (&TREE_PURPOSE (arg), &find_parameter_packs_r, 
                     &ppd, ppd.visited);
@@ -4415,7 +4433,9 @@ process_template_parm (tree list, location_t parm_loc, tree parm,
      process_template_parm could fail. */
   tree reqs = finish_shorthand_constraint (parm, constr);
 
-  pushdecl (decl);
+  decl = pushdecl (decl);
+  if (!is_non_type)
+    parm = decl;
 
   /* Build the parameter node linking the parameter declaration,
      its default argument (if any), and its constraints (if any). */
@@ -5098,7 +5118,13 @@ fixed_parameter_pack_p_1 (tree parm, struct find_parameter_pack_data *ppd)
 
   tree vec = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (parm));
   for (int i = 0; i < TREE_VEC_LENGTH (vec); ++i)
-    fixed_parameter_pack_p_1 (TREE_VALUE (TREE_VEC_ELT (vec, i)), ppd);
+    {
+      tree p = TREE_VALUE (TREE_VEC_ELT (vec, i));
+      if (template_parameter_pack_p (p))
+       /* Any packs in the type are expanded by this parameter.  */;
+      else
+       fixed_parameter_pack_p_1 (p, ppd);
+    }
 }
 
 /* PARM is a template parameter pack.  Return any parameter packs used in
@@ -6813,6 +6839,19 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
               || cxx_dialect >= cxx17)
        {
+         /* Calling build_converted_constant_expr might create a call to
+            a conversion function with a value-dependent argument, which
+            could invoke taking the address of a temporary representing
+            the result of the conversion.  */
+         if (COMPOUND_LITERAL_P (expr)
+             && CONSTRUCTOR_IS_DEPENDENT (expr)
+             && MAYBE_CLASS_TYPE_P (expr_type)
+             && TYPE_HAS_CONVERSION (expr_type))
+           {
+             expr = build1 (IMPLICIT_CONV_EXPR, type, expr);
+             IMPLICIT_CONV_EXPR_NONTYPE_ARG (expr) = true;
+             return expr;
+           }
          /* C++17: A template-argument for a non-type template-parameter shall
             be a converted constant expression (8.20) of the type of the
             template-parameter.  */
@@ -7536,6 +7575,7 @@ coerce_template_template_parms (tree parm_parms,
         args and the converted args.  If that succeeds, A is at least as
         specialized as P, so they match.*/
       tree pargs = template_parms_level_to_args (parm_parms);
+      pargs = add_outermost_template_args (outer_args, pargs);
       ++processing_template_decl;
       pargs = coerce_template_parms (arg_parms, pargs, NULL_TREE, tf_none,
                                     /*require_all*/true, /*use_default*/true);
@@ -8166,8 +8206,9 @@ coerce_template_parameter_pack (tree parms,
           int j, len = TREE_VEC_LENGTH (packed_parms);
           for (j = 0; j < len; ++j)
             {
-              tree t = TREE_TYPE (TREE_VEC_ELT (packed_parms, j));
-              if (invalid_nontype_parm_type_p (t, complain))
+              tree t = TREE_VEC_ELT (packed_parms, j);
+              if (TREE_CODE (t) == PARM_DECL
+                 && invalid_nontype_parm_type_p (TREE_TYPE (t), complain))
                 return error_mark_node;
             }
          /* We don't know how many args we have yet, just
@@ -8436,6 +8477,7 @@ coerce_template_parms (tree parms,
        arg = NULL_TREE;
 
       if (template_parameter_pack_p (TREE_VALUE (parm))
+         && (arg || !(complain & tf_partial))
          && !(arg && ARGUMENT_PACK_P (arg)))
         {
          /* Some arguments will be placed in the
@@ -9661,6 +9703,16 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
                   : (TREE_CODE (found) == TYPE_DECL
                      ? DECL_TI_TEMPLATE (found)
                      : CLASSTYPE_TI_TEMPLATE (found)));
+
+         if (DECL_CLASS_TEMPLATE_P (found)
+             && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (found)))
+           {
+             /* If this partial instantiation is specialized, we want to
+                use it for hash table lookup.  */
+             elt.tmpl = found;
+             elt.args = arglist = INNERMOST_TEMPLATE_ARGS (arglist);
+             hash = spec_hasher::hash (&elt);
+           }
        }
 
       // Build template info for the new specialization.
@@ -9668,6 +9720,7 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 
       elt.spec = t;
       slot = type_specializations->find_slot_with_hash (&elt, hash, INSERT);
+      gcc_checking_assert (*slot == NULL);
       entry = ggc_alloc<spec_entry> ();
       *entry = elt;
       *slot = entry;
@@ -11544,6 +11597,9 @@ make_fnparm_pack (tree spec_parm)
 static int
 argument_pack_element_is_expansion_p (tree arg_pack, int i)
 {
+  if (TREE_CODE (arg_pack) == ARGUMENT_PACK_SELECT)
+    /* We're being called before this happens in tsubst_pack_expansion.  */
+    arg_pack = ARGUMENT_PACK_SELECT_FROM_PACK (arg_pack);
   tree vec = ARGUMENT_PACK_ARGS (arg_pack);
   if (i >= TREE_VEC_LENGTH (vec))
     return 0;
@@ -13233,7 +13289,13 @@ tsubst_template_decl (tree t, tree args, tsubst_flags_t complain,
       hash = hash_tmpl_and_args (t, full_args);
       spec = retrieve_specialization (t, full_args, hash);
       if (spec != NULL_TREE)
-       return spec;
+       {
+         if (TYPE_P (spec))
+           /* Type partial instantiations are stored as the type by
+              lookup_template_class_1, not here as the template.  */
+           spec = CLASSTYPE_TI_TEMPLATE (spec);
+         return spec;
+       }
     }
 
   /* Make a new template decl.  It will be similar to the
@@ -13888,7 +13950,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
 
            DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
            SET_DECL_IMPLICIT_INSTANTIATION (r);
-           register_specialization (r, gen_tmpl, argvec, false, hash);
+           if (!error_operand_p (r) || (complain & tf_error))
+             register_specialization (r, gen_tmpl, argvec, false, hash);
          }
        else
          {
@@ -15575,12 +15638,23 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
            {
              /* First try name lookup to find the instantiation.  */
              r = lookup_name (DECL_NAME (t));
-             if (r && !is_capture_proxy (r))
+             if (r)
                {
-                 /* Make sure that the one we found is the one we want.  */
-                 tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
-                 if (ctx != DECL_CONTEXT (r))
-                   r = NULL_TREE;
+                 if (!VAR_P (r))
+                   {
+                     /* During error-recovery we may find a non-variable,
+                        even an OVERLOAD: just bail out and avoid ICEs and
+                        duplicate diagnostics (c++/62207).  */
+                     gcc_assert (seen_error ());
+                     return error_mark_node;
+                   }
+                 if (!is_capture_proxy (r))
+                   {
+                     /* Make sure the one we found is the one we want.  */
+                     tree ctx = enclosing_instantiation_of (DECL_CONTEXT (t));
+                     if (ctx != DECL_CONTEXT (r))
+                       r = NULL_TREE;
+                   }
                }
 
              if (r)
@@ -15616,7 +15690,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
                    }
                  gcc_assert (cp_unevaluated_operand || TREE_STATIC (r)
                              || decl_constant_var_p (r)
-                             || errorcount || sorrycount);
+                             || seen_error ());
                  if (!processing_template_decl
                      && !TREE_STATIC (r))
                    r = process_outer_var_ref (r, complain);
@@ -19400,17 +19474,10 @@ tsubst_copy_and_build (tree t,
       {
        tree r = tsubst_copy (t, args, complain, in_decl);
        /* ??? We're doing a subset of finish_id_expression here.  */
-       if (VAR_P (r)
-           && !processing_template_decl
-           && !cp_unevaluated_operand
-           && (TREE_STATIC (r) || DECL_EXTERNAL (r))
-           && CP_DECL_THREAD_LOCAL_P (r))
-         {
-           if (tree wrap = get_tls_wrapper_fn (r))
-             /* Replace an evaluated use of the thread_local variable with
-                a call to its wrapper.  */
-             r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
-         }
+       if (tree wrap = maybe_get_tls_wrapper_call (r))
+         /* Replace an evaluated use of the thread_local variable with
+            a call to its wrapper.  */
+         r = wrap;
        else if (outer_automatic_var_p (r))
          r = process_outer_var_ref (r, complain);
 
@@ -20081,7 +20148,7 @@ fn_type_unification (tree fn,
         substitution context.  */
       explicit_targs
        = (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
-                                 complain,
+                                 complain|tf_partial,
                                  /*require_all_args=*/false,
                                  /*use_default_args=*/false));
       if (explicit_targs == error_mark_node)
@@ -21002,8 +21069,15 @@ type_unification_real (tree tparms,
            }
          else
            {
+             /* Even if the call is happening in template context, getting
+                here means it's non-dependent, and a default argument is
+                considered a separate definition under [temp.decls], so we can
+                do this substitution without processing_template_decl.  This
+                is important if the default argument contains something that
+                might be instantiation-dependent like access (87480).  */
+             processing_template_decl_sentinel s;
              tree substed = NULL_TREE;
-             if (saw_undeduced == 1 && processing_template_decl == 0)
+             if (saw_undeduced == 1)
                {
                  /* First instatiate in template context, in case we still
                     depend on undeduced template parameters.  */
@@ -23547,6 +23621,11 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
       args = INNERMOST_TEMPLATE_ARGS (args);
     }
 
+  /* The caller hasn't called push_to_top_level yet, but we need
+     get_partial_spec_bindings to be done in non-template context so that we'll
+     fully resolve everything.  */
+  processing_template_decl_sentinel ptds;
+
   for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
     {
       tree spec_args;
@@ -24184,6 +24263,17 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
 
   if (DECL_CLONED_FUNCTION_P (fn))
     fn = DECL_CLONED_FUNCTION (fn);
+
+  tree orig_fn = NULL_TREE;
+  /* For a member friend template we can get a TEMPLATE_DECL.  Let's use
+     its FUNCTION_DECL for the rest of this function -- push_access_scope
+     doesn't accept TEMPLATE_DECLs.  */
+  if (DECL_FUNCTION_TEMPLATE_P (fn))
+    {
+      orig_fn = fn;
+      fn = DECL_TEMPLATE_RESULT (fn);
+    }
+
   fntype = TREE_TYPE (fn);
   spec = TYPE_RAISES_EXCEPTIONS (fntype);
 
@@ -24220,37 +24310,41 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
          push_deferring_access_checks (dk_no_deferred);
          input_location = DECL_SOURCE_LOCATION (fn);
 
-         /* A new stack interferes with pop_access_scope.  */
-         {
-           /* Set up the list of local specializations.  */
-           local_specialization_stack lss (lss_copy);
-
-           tree save_ccp = current_class_ptr;
-           tree save_ccr = current_class_ref;
-           /* If needed, set current_class_ptr for the benefit of
-              tsubst_copy/PARM_DECL.  */
-           tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
-           if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
-             {
-               tree this_parm = DECL_ARGUMENTS (tdecl);
-               current_class_ptr = NULL_TREE;
-               current_class_ref = cp_build_fold_indirect_ref (this_parm);
-               current_class_ptr = this_parm;
-             }
+         tree save_ccp = current_class_ptr;
+         tree save_ccr = current_class_ref;
+         /* If needed, set current_class_ptr for the benefit of
+            tsubst_copy/PARM_DECL.  */
+         tree tdecl = DECL_TEMPLATE_RESULT (DECL_TI_TEMPLATE (fn));
+         if (DECL_NONSTATIC_MEMBER_FUNCTION_P (tdecl))
+           {
+             tree this_parm = DECL_ARGUMENTS (tdecl);
+             current_class_ptr = NULL_TREE;
+             current_class_ref = cp_build_fold_indirect_ref (this_parm);
+             current_class_ptr = this_parm;
+           }
 
-           /* Create substitution entries for the parameters.  */
-           register_parameter_specializations (tdecl, fn);
+         /* If this function is represented by a TEMPLATE_DECL, then
+            the deferred noexcept-specification might still contain
+            dependent types, even after substitution.  And we need the
+            dependency check functions to work in build_noexcept_spec.  */
+         if (orig_fn)
+           ++processing_template_decl;
 
-           /* Do deferred instantiation of the noexcept-specifier.  */
-           noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
-                                         DEFERRED_NOEXCEPT_ARGS (noex),
-                                         tf_warning_or_error, fn,
-                                         /*function_p=*/false,
-                                         /*i_c_e_p=*/true);
-           current_class_ptr = save_ccp;
-           current_class_ref = save_ccr;
-           spec = build_noexcept_spec (noex, tf_warning_or_error);
-         }
+         /* Do deferred instantiation of the noexcept-specifier.  */
+         noex = tsubst_copy_and_build (DEFERRED_NOEXCEPT_PATTERN (noex),
+                                       DEFERRED_NOEXCEPT_ARGS (noex),
+                                       tf_warning_or_error, fn,
+                                       /*function_p=*/false,
+                                       /*i_c_e_p=*/true);
+
+         current_class_ptr = save_ccp;
+         current_class_ref = save_ccr;
+
+         /* Build up the noexcept-specification.  */
+         spec = build_noexcept_spec (noex, tf_warning_or_error);
+
+         if (orig_fn)
+           --processing_template_decl;
 
          pop_deferring_access_checks ();
          pop_access_scope (fn);
@@ -24270,6 +24364,8 @@ maybe_instantiate_noexcept (tree fn, tsubst_flags_t complain)
        }
 
       TREE_TYPE (fn) = build_exception_variant (fntype, spec);
+      if (orig_fn)
+       TREE_TYPE (orig_fn) = TREE_TYPE (fn);
     }
 
   FOR_EACH_CLONE (clone, fn)
@@ -25683,6 +25779,12 @@ type_dependent_expression_p (tree expression)
       || TREE_CODE (expression) == WILDCARD_DECL)
     return true;
 
+  /* A lambda-expression in template context is dependent.  dependent_type_p is
+     true for a lambda in the scope of a class or function template, but that
+     doesn't cover all template contexts, like a default template argument.  */
+  if (TREE_CODE (expression) == LAMBDA_EXPR)
+    return true;
+
   /* A fold expression is type-dependent. */
   if (TREE_CODE (expression) == UNARY_LEFT_FOLD_EXPR
       || TREE_CODE (expression) == UNARY_RIGHT_FOLD_EXPR
@@ -27418,6 +27520,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
   if (init && undeduced_auto_decl (init))
     return type;
 
+  /* We may be doing a partial substitution, but we still want to replace
+     auto_node.  */
+  complain &= ~tf_partial;
+
   if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
     /* C++17 class template argument deduction.  */
     return do_class_deduction (type, tmpl, init, flags, complain);