+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
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
}
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);
}
+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
--- /dev/null
+// 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; }
--- /dev/null
+// 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 ();
+};
--- /dev/null
+// { 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; }