Commit 5837edca by Martin Sebor Committed by Martin Sebor

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
parent 0cbe950d
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
......
......@@ -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);
}
......
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
......
// 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; }
// 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 ();
};
// { 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; }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment