From: Martin Sebor Date: Tue, 19 Dec 2017 22:09:00 +0000 (+0000) Subject: PR c++/83394 - always_inline vs. noinline no longer diagnosed X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=5837edca5cf5eb7cc45a2a61f69543264b50bbc8;p=gcc.git PR c++/83394 - always_inline vs. noinline no longer diagnosed 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8a66949be12..831cb23edd9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-12-19 Martin Sebor + + 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 * name-lookup.c (get_std_name_hint): Replace Yoda conditions with diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 5a87f30fa40..d5111d58cca 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7a52c37bda8..cb9e01223d4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2017-12-19 Martin Sebor + + 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 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 index 00000000000..a70176b14b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wattributes-3.C @@ -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 index 00000000000..c925225d3a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wattributes-4.C @@ -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 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 index 00000000000..70116c92ae8 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wattributes-5.C @@ -0,0 +1,34 @@ +// { dg-do compile } +// { dg-options "-Wattributes" } + +#define ATTR(list) __attribute__ (list) + +template +struct A +{ + int __attribute__ ((noinline)) + f (); // { dg-message "previous declaration here" } +}; + +template +int __attribute__ ((always_inline)) +A::f () // { dg-warning "ignoring attribute .always_inline. because it conflicts with attribute .noinline." } */ +{ return 0; } + + +template +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; }