Fix array decay handling in constant expressions.
authorJason Merrill <jason@redhat.com>
Fri, 9 Jun 2017 20:13:44 +0000 (16:13 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 9 Jun 2017 20:13:44 +0000 (16:13 -0400)
* parser.c (cp_parser_constant_expression): Check
potential_rvalue_constant_expression after decay_conversion.
* pt.c (convert_nontype_argument): Don't require linkage in C++17.

From-SVN: r249079

gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/template/function1.C
gcc/testsuite/g++.dg/template/nontype-array1.C [new file with mode: 0644]

index 944b69596fe319c1b1e17d26198a0767b0a79deb..7bc9c204a2907152b6d26532f57539b8af961640 100644 (file)
@@ -1,5 +1,9 @@
 2017-06-09  Jason Merrill  <jason@redhat.com>
 
+       * parser.c (cp_parser_constant_expression): Check
+       potential_rvalue_constant_expression after decay_conversion.
+       * pt.c (convert_nontype_argument): Don't require linkage in C++17.
+
        PR c++/80384 - ICE with dependent noexcept-specifier
        * pt.c (dependent_type_p_r) [FUNCTION_TYPE]: Check for dependent
        noexcept-specifier.
index 891341d1e8132784cdd1bdb8ce24a77c1bfe7ddd..78f7d66f3bbe08a10e611363a0a29e0c8115ee67 100644 (file)
@@ -9462,10 +9462,14 @@ cp_parser_constant_expression (cp_parser* parser,
       /* Require an rvalue constant expression here; that's what our
         callers expect.  Reference constant expressions are handled
         separately in e.g. cp_parser_template_argument.  */
-      bool is_const = potential_rvalue_constant_expression (expression);
+      tree decay = expression;
+      if (TREE_TYPE (expression)
+         && TREE_CODE (TREE_TYPE (expression)) == ARRAY_TYPE)
+       decay = build_address (expression);
+      bool is_const = potential_rvalue_constant_expression (decay);
       parser->non_integral_constant_expression_p = !is_const;
       if (!is_const && !allow_non_constant_p)
-       require_potential_rvalue_constant_expression (expression);
+       require_potential_rvalue_constant_expression (decay);
     }
   if (allow_non_constant_p)
     *non_constant_p = parser->non_integral_constant_expression_p;
index 99f5b123a84ef0e6a266d55ce7b482d66e999b39..d8f8d467200974d9ff92c4eb984112d8f409f00b 100644 (file)
@@ -6683,13 +6683,46 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
                       expr, type, decl);
              return NULL_TREE;
            }
-         else if (cxx_dialect >= cxx11 && decl_linkage (decl) == lk_none)
+         else if ((cxx_dialect >= cxx11 && cxx_dialect < cxx1z)
+                  && decl_linkage (decl) == lk_none)
            {
              if (complain & tf_error)
                error ("%qE is not a valid template argument of type %qT "
                       "because %qD has no linkage", expr, type, decl);
              return NULL_TREE;
            }
+         /* C++17: For a non-type template-parameter of reference or pointer
+            type, the value of the constant expression shall not refer to (or
+            for a pointer type, shall not be the address of):
+              * a subobject (4.5),
+              * a temporary object (15.2),
+              * a string literal (5.13.5),
+              * the result of a typeid expression (8.2.8), or
+              * a predefined __func__ variable (11.4.1).  */
+         else if (DECL_ARTIFICIAL (decl))
+           {
+             if (complain & tf_error)
+               error ("the address of %qD is not a valid template argument",
+                      decl);
+             return NULL_TREE;
+           }
+         else if (!same_type_ignoring_top_level_qualifiers_p
+                  (strip_array_types (TREE_TYPE (type)),
+                   strip_array_types (TREE_TYPE (decl))))
+           {
+             if (complain & tf_error)
+               error ("the address of the %qT subobject of %qD is not a "
+                      "valid template argument", TREE_TYPE (type), decl);
+             return NULL_TREE;
+           }
+         else if (!TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+           {
+             if (complain & tf_error)
+               error ("the address of %qD is not a valid template argument "
+                      "because it does not have static storage duration",
+                      decl);
+             return NULL_TREE;
+           }
        }
 
       expr = decay_conversion (expr, complain);
index f2345855ed972d3770664a8b7638d359af14e032..4bab2e4e9bf8704f4cebd032dab4e595bfb58c54 100644 (file)
@@ -1,10 +1,8 @@
 // PR c++/38647
-// { dg-do compile { target { ! c++1z } } }
-// { dg-prune-output "note" }
 
 template<const char *, int> struct A {};
 const char func[] = "abc";
-template<int N> struct A<func, N> {};  // { dg-error "cannot appear|is invalid|not a valid|constant expression" }
+template<int N> struct A<func, N> {};  // { dg-error "cannot appear|is invalid|not a valid|constant expression" "" { target c++98_only } }
 
 char a1[1];
 A<a1, 0> a;
diff --git a/gcc/testsuite/g++.dg/template/nontype-array1.C b/gcc/testsuite/g++.dg/template/nontype-array1.C
new file mode 100644 (file)
index 0000000..cf21908
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+
+template <char const* STR>
+class Message {
+};
+
+extern char const s1[] = "hi";
+char const s2[] = "hi";
+constexpr char const s3[] = "hi";  // OK since C++11
+
+constexpr char const * f() { return s3; }
+
+int main()
+{
+  Message<s1> m1;  // OK (all versions)
+  Message<s2> m2;  // OK for clang since C++14, for gcc since C++17
+  Message<s3> m3;  // OK for clang/gcc since C++11
+
+  static char const s4[] = "hi";
+  static constexpr char const s5[] = "hi";  // OK since C++11
+  Message<s4> m4;  // { dg-error "no linkage" "" { target c++14_down } }
+  Message<s5> m5;  // { dg-error "no linkage" "" { target c++14_down } }
+  Message<f()> m6; // { dg-error "" "" { target c++14_down } }
+
+  char const s8[] = "hi";
+  Message<s8> m8;  // { dg-error "" }
+}