Hi!

As mentioned in the PR, C++98 didn't allow static data members nor any
members with reference type, and r211318 guarded all that with cxx_dialect <
cxx11.  Which is correct for the VAR_P check, but as C++11 and later
says that non-static data members of reference type are ill-formed in
unions, for C++11 and later we need to allow reference type on static data
members and disallow it on FIELD_DECLs.

On some testcases the invalid C++11+ would work fine, but on the attached
pr78890-1.C g++ ICEd.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-01-02  Jakub Jelinek  <ja...@redhat.com>

        PR c++/78890
        * class.c (check_field_decls): Diagnose REFERENCE_TYPE fields in
        unions even for C++11 and later.

        * g++.dg/init/ref14.C: Expect error even in C++11 and later.
        * g++.dg/init/union1.C: Likewise.
        * g++.dg/cpp0x/union6.C: Expect errors.
        * g++.dg/cpp0x/union8.C: New test.
        * g++.dg/cpp0x/pr78890-1.C: New test.
        * g++.dg/cpp0x/pr78890-2.C: New test.

--- gcc/cp/class.c.jj   2017-01-01 12:45:44.000000000 +0100
+++ gcc/cp/class.c      2017-01-02 10:03:43.119034899 +0100
@@ -3759,16 +3759,17 @@ check_field_decls (tree t, tree *access_
       /* When this goes into scope, it will be a non-local reference.  */
       DECL_NONLOCAL (x) = 1;
 
-      if (TREE_CODE (t) == UNION_TYPE
-         && cxx_dialect < cxx11)
+      if (TREE_CODE (t) == UNION_TYPE)
        {
          /* [class.union] (C++98)
 
             If a union contains a static data member, or a member of
             reference type, the program is ill-formed.
 
-            In C++11 this limitation doesn't exist anymore.  */
-         if (VAR_P (x))
+            In C++11 [class.union] says:
+            If a union contains a non-static data member of reference type
+            the program is ill-formed.  */
+         if (VAR_P (x) && cxx_dialect < cxx11)
            {
              error ("in C++98 %q+D may not be static because it is "
                     "a member of a union", x);
@@ -3776,9 +3777,18 @@ check_field_decls (tree t, tree *access_
            }
          if (TREE_CODE (type) == REFERENCE_TYPE)
            {
-             error ("in C++98 %q+D may not have reference type %qT "
-                    "because it is a member of a union", x, type);
-             continue;
+             if (cxx_dialect < cxx11)
+               {
+                 error ("in C++98 %q+D may not have reference type %qT "
+                        "because it is a member of a union", x, type);
+                 continue;
+               }
+             else if (TREE_CODE (x) == FIELD_DECL)
+               {
+                 error ("non-static data member %q+D in a union may not "
+                        "have reference type %qT", x, type);
+                 continue;
+               }
            }
        }
 
--- gcc/testsuite/g++.dg/init/ref14.C.jj        2014-06-09 11:01:13.000000000 
+0200
+++ gcc/testsuite/g++.dg/init/ref14.C   2017-01-02 10:10:47.629616381 +0100
@@ -4,7 +4,7 @@
 
 union A
 {
-  int &i; // { dg-error "may not have reference type" "" { target { ! c++11 } 
} }
+  int &i; // { dg-error "may not have reference type" }
 };
 
 void foo()
--- gcc/testsuite/g++.dg/init/union1.C.jj       2014-06-09 11:01:13.000000000 
+0200
+++ gcc/testsuite/g++.dg/init/union1.C  2017-01-02 10:11:05.667386144 +0100
@@ -1,5 +1,5 @@
 // PR c++/14401
 
 union U {
-  int& i; // { dg-error "reference type" "" { target { ! c++11 } } }
+  int& i; // { dg-error "reference type" }
 };
--- gcc/testsuite/g++.dg/cpp0x/union6.C.jj      2014-06-09 11:01:13.000000000 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/union6.C 2017-01-02 10:10:20.152967097 +0100
@@ -12,9 +12,9 @@ union Test2 {
 const int Test2::kConstant = 10;
 
 union Test3 {
-  int& kConstant;
+  int& kConstant;      // { dg-error "may not have reference type" }
 };
 
 union Test4 {
-  const int& kConstant = 10;
+  const int& kConstant = 10;   // { dg-error "may not have reference type" }
 };
--- gcc/testsuite/g++.dg/cpp0x/union8.C.jj      2017-01-02 10:30:59.981111680 
+0100
+++ gcc/testsuite/g++.dg/cpp0x/union8.C 2017-01-02 10:32:05.715270255 +0100
@@ -0,0 +1,26 @@
+// PR c++/78890
+// { dg-do compile { target c++11 } }
+
+union Test1 {
+  static int kConstant;
+};
+
+union Test2 {
+  static const int kConstant;
+};
+
+const int Test2::kConstant = 10;
+
+int k;
+
+union Test3 {
+  static int& kRef;
+};
+
+int& Test3::kRef = k;
+
+union Test4 {
+  static const int& kRef;
+};
+
+const int& Test4::kRef = 10;
--- gcc/testsuite/g++.dg/cpp0x/pr78890-1.C.jj   2017-01-02 10:24:42.406944789 
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr78890-1.C      2017-01-02 10:24:38.101999895 
+0100
@@ -0,0 +1,13 @@
+// PR c++/78890
+// { dg-do compile { target c++11 } }
+
+int
+main()
+{
+  union {
+    int a;
+    int &b = a;                // { dg-error "may not have reference type" }
+  };
+  a = 1;
+  auto c = b + 1;
+}
--- gcc/testsuite/g++.dg/cpp0x/pr78890-2.C.jj   2017-01-02 10:24:45.619903662 
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr78890-2.C      2017-01-02 10:24:26.960142515 
+0100
@@ -0,0 +1,44 @@
+// PR c++/78890
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+int
+foo ()
+{
+  union {
+    int a;
+    int &b = a;                        // { dg-error "may not have reference 
type" }
+  };
+  a = 1;
+  auto c = b + 1;
+  return c;
+}
+
+template <typename T>
+T
+bar ()
+{
+  union {
+    T a;
+    T &b = a;                  // { dg-error "may not have reference type" }
+  };
+  a = 1;
+  auto c = b + 1;
+  return c;
+}
+
+template <typename T, typename U>
+T baz()
+{
+  union {
+    T a;
+    U b = a;                   // { dg-error "may not have reference type" }
+  };
+  a = 1;
+  auto c = b + 1;
+  return c;
+}
+
+int a = foo<int> ();
+int b = bar<int> ();
+int c = baz<int, int &> ();

        Jakub

Reply via email to