PR c++/83394 - always_inline vs. noinline no longer diagnosed
authorMartin Sebor <msebor@redhat.com>
Tue, 19 Dec 2017 22:09:00 +0000 (22:09 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Tue, 19 Dec 2017 22:09:00 +0000 (15:09 -0700)
PR c++/83394 - always_inline vs. noinline no longer diagnosed
PR c++/83322 - ICE: tree check: expected class ‘type’, have ‘exceptional’

gcc/cp/ChangeLog:

PR c++/83394
PR c++/83322
* decl2.c (cplus_decl_attributes): Look up member functions
in the scope of their class.

gcc/testsuite/ChangeLog:

PR c++/83394
* g++.dg/Wattributes-3.C: New test.
* g++.dg/Wattributes-4.C: New test.
* g++.dg/Wattributes-5.C: New test.

From-SVN: r255844

gcc/cp/ChangeLog
gcc/cp/decl2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/Wattributes-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/Wattributes-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/Wattributes-5.C [new file with mode: 0644]

index 8a66949be12e545f412b3c93a40f0bafbaf8e959..831cb23edd902f899219ed871cb7f0dff3faf35a 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-19  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/83394
+       PR c++/83322
+       * decl2.c (cplus_decl_attributes): Look up member functions
+       in the scope of their class.
+
 2017-12-19  Jakub Jelinek  <jakub@redhat.com>
 
        * name-lookup.c (get_std_name_hint): Replace Yoda conditions with
index 5a87f30fa403bba49c9f0fb6c5afc9ac980bf7c8..d5111d58cca10263f3632f737e2a9be39fc39122 100644 (file)
@@ -1445,6 +1445,52 @@ cp_omp_mappable_type (tree type)
   return true;
 }
 
+/* Return the last pushed declaration for the symbol DECL or NULL
+   when no such declaration exists.  */
+
+static tree
+find_last_decl (tree decl)
+{
+  tree last_decl = NULL_TREE;
+
+  if (tree name = DECL_P (decl) ? DECL_NAME (decl) : NULL_TREE)
+    {
+      /* Look up the declaration in its scope.  */
+      tree pushed_scope = NULL_TREE;
+      if (tree ctype = DECL_CONTEXT (decl))
+       pushed_scope = push_scope (ctype);
+
+      last_decl = lookup_name (name);
+
+      if (pushed_scope)
+       pop_scope (pushed_scope);
+
+      /* The declaration may be a member conversion operator
+        or a bunch of overfloads (handle the latter below).  */
+      if (last_decl && BASELINK_P (last_decl))
+       last_decl = BASELINK_FUNCTIONS (last_decl);
+    }
+
+  if (!last_decl)
+    return NULL_TREE;
+
+  if (DECL_P (last_decl) || TREE_CODE (last_decl) == OVERLOAD)
+    {
+      /* A set of overloads of the same function.  */
+      for (lkp_iterator iter (last_decl); iter; ++iter)
+       {
+         if (TREE_CODE (*iter) == OVERLOAD)
+           continue;
+
+         if (decls_match (decl, *iter, /*record_decls=*/false))
+           return *iter;
+       }
+      return NULL_TREE;
+    }
+
+  return NULL_TREE;
+}
+
 /* Like decl_attributes, but handle C++ complexity.  */
 
 void
@@ -1496,28 +1542,7 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
     }
   else
     {
-      tree last_decl = (DECL_P (*decl) && DECL_NAME (*decl)
-                       ? lookup_name (DECL_NAME (*decl)) : NULL_TREE);
-
-      if (last_decl && TREE_CODE (last_decl) == OVERLOAD)
-       for (ovl_iterator iter (last_decl, true); ; ++iter)
-         {
-           if (!iter)
-             {
-               last_decl = NULL_TREE;
-               break;
-             }
-
-           if (TREE_CODE (*iter) == OVERLOAD)
-             continue;
-
-           if (decls_match (*decl, *iter, /*record_decls=*/false))
-             {
-               last_decl = *iter;
-               break;
-             }
-         }
-
+      tree last_decl = find_last_decl (*decl);
       decl_attributes (decl, attributes, flags, last_decl);
     }
 
index 7a52c37bda81bbbf2955bd937d8928dc1acd50d0..cb9e01223d42f0ee50956db092b2bf85006e53a4 100644 (file)
@@ -1,3 +1,10 @@
+2017-12-19  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/83394
+       * g++.dg/Wattributes-3.C: New test.
+       * g++.dg/Wattributes-4.C: New test.
+       * g++.dg/Wattributes-5.C: New test.
+
 2017-12-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/82975
diff --git a/gcc/testsuite/g++.dg/Wattributes-3.C b/gcc/testsuite/g++.dg/Wattributes-3.C
new file mode 100644 (file)
index 0000000..a70176b
--- /dev/null
@@ -0,0 +1,90 @@
+// PR c++/83394 - always_inline vs. noinline no longer diagnosed
+// { dg-do compile }
+// { dg-options "-Wattributes" }
+
+#define ATTR(list) __attribute__ (list)
+
+struct A
+{
+  ATTR ((__noinline__)) operator int ();
+};
+
+ATTR ((__always_inline__))
+A::operator int ()            // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." }
+{
+  return 0;
+}
+
+
+struct B
+{
+  operator char () const;
+  ATTR ((__always_inline__)) operator int () const;
+};
+
+B::operator char () const { return 0; }
+
+ATTR ((__noinline__))
+B::operator int () const      // { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." }
+{
+  return 0;
+}
+
+
+struct C
+{
+  operator char ();
+  ATTR ((__always_inline__)) operator short ();
+  operator int ();
+  ATTR ((__noinline__)) operator long ();
+};
+
+C::operator char () { return 0; }
+
+ATTR ((__noinline__))
+C::operator short ()           // { dg-warning "ignoring attribute .noinline. because it conflicts with attribute .always_inline." }
+{ return 0; }
+
+inline ATTR ((__noinline__))
+C::operator int ()
+{ return 0; }
+
+
+ATTR ((__always_inline__))
+C::operator long ()           // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." }
+{ return 0; }
+
+
+struct D
+{
+  int foo ();
+  int foo (int);
+  int ATTR ((const)) foo (int, int);
+  int ATTR ((pure)) foo (int, int, int);
+
+  int ATTR ((const)) foo (int, int, int, int);
+
+  int foo (int, int, int, int, int);
+};
+
+int ATTR ((const))
+D::foo ()
+{ return 0; }
+
+int ATTR ((pure))
+D::foo (int)
+{ return 0; }
+
+int ATTR ((pure))
+D::foo (int, int)             // { dg-warning "ignoring attribute .pure. because it conflicts with attribute .const." }
+{ return 0; }
+
+int ATTR ((const))
+D::foo (int, int, int)        // { dg-warning "ignoring attribute .const. because it conflicts with attribute .pure." }
+{ return 0; }
+
+int
+D::foo (int, int, int, int) { return 0; }
+
+int ATTR ((const))
+D::foo (int, int, int, int, int) { return 0; }
diff --git a/gcc/testsuite/g++.dg/Wattributes-4.C b/gcc/testsuite/g++.dg/Wattributes-4.C
new file mode 100644 (file)
index 0000000..c925225
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/83322 - ICE: tree check: expected class ‘type’, have ‘exceptional’
+// (baselink) in diag_attr_exclusions, at attribs.c:393
+// { dg-do compile }
+// { dg-options "-Wattributes" }
+
+#define ATTR(list) __attribute__ (list)
+
+// Test case from comment #0.
+struct A0
+{
+  template <class T> operator T();
+  ATTR ((always_inline)) operator int();
+};
+
+// Test case from comment #4.
+struct A1
+{
+  void foo();
+};
+
+struct B
+{
+  bool foo;
+};
+
+struct C: A1, B
+{
+  ATTR ((warn_unused_result)) int foo ();
+};
diff --git a/gcc/testsuite/g++.dg/Wattributes-5.C b/gcc/testsuite/g++.dg/Wattributes-5.C
new file mode 100644 (file)
index 0000000..70116c9
--- /dev/null
@@ -0,0 +1,34 @@
+// { dg-do compile }
+// { dg-options "-Wattributes" }
+
+#define ATTR(list) __attribute__ (list)
+
+template <int>
+struct A
+{
+  int __attribute__ ((noinline))
+  f ();                       // { dg-message "previous declaration here" }
+};
+
+template <int N>
+int __attribute__ ((always_inline))
+A<N>::f ()                    // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." } */
+{ return 0; }
+
+
+template <int>
+struct B
+{
+  int __attribute__ ((always_inline))
+  f ();
+};
+
+template <>
+inline int __attribute__ ((always_inline))
+B<0>::f ()
+{ return 0; }
+
+template <>
+int __attribute__ ((noinline))
+B<1>::f ()
+{ return 1; }