Remember the location of a variable template-id.
authorJason Merrill <jason@redhat.com>
Wed, 27 Nov 2019 03:14:33 +0000 (22:14 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 27 Nov 2019 03:14:33 +0000 (22:14 -0500)
I noticed that tsubst of a TEMPLATE_ID_EXPR was losing the location
information from its EXPR_LOCATION.  Then I noticed that
cxx_eval_constant_expression was also throwing away location information for
variable references.

* pt.c (tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: Remember the
location of a variable template-id.
* constexpr.c (cxx_eval_constant_expression): Get expr location
before stripping location wrappers.
(non_const_var_error): Take location argument.

From-SVN: r278755

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/concepts/pr67595.C
gcc/testsuite/g++.dg/cpp1y/var-templ64.C [new file with mode: 0644]

index 9f27a58..6cf8579 100644 (file)
@@ -1,3 +1,11 @@
+2019-11-26  Jason Merrill  <jason@redhat.com>
+
+       * pt.c (tsubst_copy_and_build) [TEMPLATE_ID_EXPR]: Remember the
+       location of a variable template-id.
+       * constexpr.c (cxx_eval_constant_expression): Get expr location
+       before stripping location wrappers.
+       (non_const_var_error): Take location argument.
+
 2019-11-26  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * typeck.c (cp_build_unary_op): Consistently use the accurate
index 658455c..f648b1d 100644 (file)
@@ -3786,27 +3786,27 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
    cxx_eval_constant_expression.  */
 
 static void
-non_const_var_error (tree r)
+non_const_var_error (location_t loc, tree r)
 {
   auto_diagnostic_group d;
   tree type = TREE_TYPE (r);
   if (DECL_NAME (r) == heap_uninit_identifier
       || DECL_NAME (r) == heap_identifier)
     {
-      error ("the content of uninitialized storage is not usable "
-            "in a constant expression");
+      error_at (loc, "the content of uninitialized storage is not usable "
+               "in a constant expression");
       inform (DECL_SOURCE_LOCATION (r), "allocated here");
       return;
     }
   if (DECL_NAME (r) == heap_deleted_identifier)
     {
-      error ("use of allocated storage after deallocation in a "
-            "constant expression");
+      error_at (loc, "use of allocated storage after deallocation in a "
+               "constant expression");
       inform (DECL_SOURCE_LOCATION (r), "allocated here");
       return;
     }
-  error ("the value of %qD is not usable in a constant "
-        "expression", r);
+  error_at (loc, "the value of %qD is not usable in a constant "
+           "expression", r);
   /* Avoid error cascade.  */
   if (DECL_INITIAL (r) == error_mark_node)
     return;
@@ -4765,6 +4765,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       return t;
     }
 
+  location_t loc = cp_expr_loc_or_input_loc (t);
+
   STRIP_ANY_LOCATION_WRAPPER (t);
 
   if (CONSTANT_CLASS_P (t))
@@ -4794,7 +4796,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
   if (++ctx->global->constexpr_ops_count >= constexpr_ops_limit)
     {
       if (!ctx->quiet)
-       error_at (cp_expr_loc_or_input_loc (t),
+       error_at (loc,
                  "%<constexpr%> evaluation operation count exceeds limit of "
                  "%wd (use %<-fconstexpr-ops-limit=%> to increase the limit)",
                  constexpr_ops_limit);
@@ -4877,7 +4879,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (DECL_P (r))
        {
          if (!ctx->quiet)
-           non_const_var_error (r);
+           non_const_var_error (loc, r);
          *non_constant_p = true;
        }
       break;
@@ -5086,9 +5088,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                          jump_target);
        if (!CLEANUP_EH_ONLY (t) && !*non_constant_p)
          {
-           location_t loc = input_location;
-           if (EXPR_HAS_LOCATION (t))
-             input_location = EXPR_LOCATION (t);
+           iloc_sentinel ils (loc);
            /* Also evaluate the cleanup.  If we weren't skipping at the
               start of the CLEANUP_BODY, change jump_target temporarily
               to &initial_jump_target, so that even a return or break or
@@ -5097,7 +5097,6 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                                          non_constant_p, overflow_p,
                                          jump_target ? &initial_jump_target
                                          : NULL);
-           input_location = loc;
          }
       }
       break;
@@ -5365,7 +5364,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       if (REINTERPRET_CAST_P (t))
        {
          if (!ctx->quiet)
-           error_at (cp_expr_loc_or_input_loc (t),
+           error_at (loc,
                      "%<reinterpret_cast%> is not a constant expression");
          *non_constant_p = true;
          return t;
@@ -5405,7 +5404,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                if (TYPE_REF_P (type))
                  {
                    if (!ctx->quiet)
-                     error_at (cp_expr_loc_or_input_loc (t),
+                     error_at (loc,
                                "dereferencing a null pointer");
                    *non_constant_p = true;
                    return t;
@@ -5417,7 +5416,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                    if (!can_convert (type, from, tf_none))
                      {
                        if (!ctx->quiet)
-                         error_at (cp_expr_loc_or_input_loc (t),
+                         error_at (loc,
                                    "conversion of %qT null pointer to %qT "
                                    "is not a constant expression",
                                    from, type);
@@ -5432,8 +5431,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
                     reinterpret_cast<void*>(sizeof 0)
                */
                if (!ctx->quiet)
-                 error_at (cp_expr_loc_or_input_loc (t),
-                           "%<reinterpret_cast<%T>(%E)%> is not "
+                 error_at (loc, "%<reinterpret_cast<%T>(%E)%> is not "
                            "a constant expression",
                            type, op);
                *non_constant_p = true;
@@ -5534,8 +5532,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case BASELINK:
     case OFFSET_REF:
       if (!ctx->quiet)
-        error_at (cp_expr_loc_or_input_loc (t),
-                 "expression %qE is not a constant expression", t);
+       error_at (loc, "expression %qE is not a constant expression", t);
       *non_constant_p = true;
       break;
 
@@ -5552,8 +5549,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
            || !DECL_P (get_base_address (TREE_OPERAND (obj, 0))))
          {
            if (!ctx->quiet)
-             error_at (cp_expr_loc_or_input_loc (t),
-                       "expression %qE is not a constant expression", t);
+             error_at (loc, "expression %qE is not a constant expression", t);
            *non_constant_p = true;
            return t;
          }
@@ -5661,7 +5657,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
 
     case ASM_EXPR:
       if (!ctx->quiet)
-       inline_asm_in_constexpr_error (cp_expr_loc_or_input_loc (t));
+       inline_asm_in_constexpr_error (loc);
       *non_constant_p = true;
       return t;
 
@@ -6724,7 +6720,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
          && !is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false))
         {
           if (flags & tf_error)
-            non_const_var_error (t);
+           non_const_var_error (loc, t);
           return false;
         }
       return true;
index 78b78ba..a11718e 100644 (file)
@@ -18870,7 +18870,12 @@ tsubst_copy_and_build (tree t,
          }
 
        if (variable_template_p (templ))
-         RETURN (lookup_and_finish_template_variable (templ, targs, complain));
+         {
+           tree r = lookup_and_finish_template_variable (templ, targs,
+                                                         complain);
+           r = maybe_wrap_with_location (r, EXPR_LOCATION (t));
+           RETURN (r);
+         }
 
        if (TREE_CODE (templ) == COMPONENT_REF)
          {
index 7199e05..029ec7a 100644 (file)
@@ -9,6 +9,6 @@ template <class X> bool input_iterator{weak_input_iterator<X>}; // { dg-warning
 template <class X> bool forward_iterator{input_iterator<X>};
 template <class X> bool bidirectional_iterator{forward_iterator<X>};
 template <class X>
-concept bool random_access_iterator{bidirectional_iterator<X>};
+concept bool random_access_iterator{bidirectional_iterator<X>}; // { dg-error "constant" }
 void fn1(random_access_iterator);
 int main() { fn1(0); }  // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ64.C b/gcc/testsuite/g++.dg/cpp1y/var-templ64.C
new file mode 100644 (file)
index 0000000..4e2b43b
--- /dev/null
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++14 } }
+
+template <class T> T var = T();
+
+template <class T>
+void f()
+{
+  constexpr T i = var<T>;      // { dg-error "19:var" }
+}
+
+int main()
+{
+  f<int>();
+}