diff options
Diffstat (limited to 'gcc/testsuite/g++.dg/ext')
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attr-ifunc-1.C | 34 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attr-ifunc-2.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attr-ifunc-3.C | 23 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attr-ifunc-4.C | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/ext/attr-ifunc-5.C | 45 |
5 files changed, 96 insertions, 30 deletions
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C index 2c7bba12959..4a29e8bb4d6 100644 --- a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C +++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C @@ -4,26 +4,33 @@ struct Klass { + int a[4]; + int implementation (); int magic (); - typedef int (Klass::*MemFuncPtr)(); + /* An ifunc resolver must return a pointer to an ordinary (non-member) + function. To make it possible to use ifunc with member functions, + the resolver must convert a member function pointer to an ordinary + function pointer (slicing off the high word). */ + typedef int Func (Klass*); - static MemFuncPtr resolver (); + static Func* resolver (); }; -Klass::MemFuncPtr p = &Klass::implementation; - -int Klass::implementation (void) +int Klass::implementation () { __builtin_printf ("'ere I am JH\n"); - return 1234; + return a[0] + a[1] + a[2] + a[3]; } - -Klass::MemFuncPtr Klass::resolver (void) +Klass::Func* Klass::resolver (void) { - return &Klass::implementation; + /* GCC guarantees this conversion to be safe and the resulting pointer + usable to call the member function using ordinary (i.e., non-member) + function call syntax. */ + + return reinterpret_cast<Func*>(&Klass::implementation); } int f (void) __attribute__ ((ifunc ("foo"))); @@ -32,11 +39,16 @@ typedef int (F)(void); extern "C" F* foo () { return 0; } -int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv"))); +int Klass::magic () __attribute__ ((ifunc ("_ZN5Klass8resolverEv"))); int main () { Klass obj; - return !(obj.magic () == 1234); + obj.a[0] = 1; + obj.a[1] = 2; + obj.a[2] = 3; + obj.a[3] = 4; + + return !(obj.magic () == 10); } diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C index 1fc940bb7dd..e5be3d29aba 100644 --- a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C +++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C @@ -9,9 +9,9 @@ struct Klass int implementation (); int magic (); - typedef int (Klass::*MemFuncPtr)(); + typedef int Func (Klass*); - static MemFuncPtr resolver (); + static Func* resolver (); }; int Klass::implementation (void) @@ -20,9 +20,13 @@ int Klass::implementation (void) return 0; } -Klass::MemFuncPtr Klass::resolver (void) +Klass::Func* Klass::resolver (void) { - return &Klass::implementation; + /* GCC guarantees this conversion to be safe and the resulting pointer + usable to call the member function using ordinary (i.e., non-member) + function call syntax. */ + + return reinterpret_cast<Func*>(&Klass::implementation); } int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv"))); diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C index 04206a126e8..6d494244331 100644 --- a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C +++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C @@ -6,23 +6,29 @@ struct Klass { + int a[4]; + int implementation (); int magic (); - typedef int (Klass::*MemFuncPtr)(); + typedef int Func (Klass*); - static MemFuncPtr resolver (); + static Func* resolver (); }; int Klass::implementation (void) { printf ("'ere I am JH\n"); - return 0; + return a[0] + a[1] + a[2] + a[3]; } -Klass::MemFuncPtr Klass::resolver (void) +Klass::Func* Klass::resolver () { - return &Klass::implementation; + /* GCC guarantees this conversion to be safe and the resulting pointer + usable to call the member function using ordinary (i.e., non-member) + function call syntax. */ + + return reinterpret_cast<Func*>(&Klass::implementation); } int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv"))); @@ -36,5 +42,10 @@ int main () { Klass obj; - return Foo (obj, &Klass::magic) != 0; + obj.a[0] = 1; + obj.a[1] = 2; + obj.a[2] = 3; + obj.a[3] = 4; + + return Foo (obj, &Klass::magic) != 10; } diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C index 3127193147e..f71dc3b9ba9 100644 --- a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C +++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C @@ -14,9 +14,9 @@ struct Klassier : Klass int implementation (); int magic (); - typedef int (Klassier::*MemFuncPtr)(); + typedef int Func (Klass*); - static MemFuncPtr resolver (); + static Func* resolver (); }; int Klassier::implementation (void) @@ -25,9 +25,13 @@ int Klassier::implementation (void) return 0; } -Klassier::MemFuncPtr Klassier::resolver (void) +Klassier::Func* Klassier::resolver () { - return &Klassier::implementation; + /* GCC guarantees this conversion to be safe and the resulting pointer + usable to call the member function using ordinary (i.e., non-member) + function call syntax. */ + + return reinterpret_cast<Func*>(&Klassier::implementation); } int Klassier::magic (void) __attribute__ ((ifunc ("_ZN8Klassier8resolverEv"))); diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C index 05855dd20c0..fd8bcff79b7 100644 --- a/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C +++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C @@ -1,15 +1,21 @@ // PR c/81854 - weak alias of an incompatible symbol accepted // { dg-do compile } // { dg-require-ifunc "" } */ +// { dg-options "-Wextra -Wno-pmf-conversions" } struct Klass { int implementation (); - const char* magic (); + int good_magic (); + int iffy_magic (); + const char* bad_magic (); + typedef int (Func)(Klass*); typedef int (Klass::*MemFuncPtr)(); - static MemFuncPtr resolver (); + static Func* good_resolver (); + static void* iffy_resolver (); + static MemFuncPtr bad_resolver (); }; int Klass::implementation (void) @@ -17,13 +23,42 @@ int Klass::implementation (void) return 0; } -const char* __attribute__ ((ifunc ("_ZN5Klass8resolverEv"))) - Klass::magic (); // { dg-warning "alias between functions of incompatible types" } +// Verify no warning for the expected/compatible declaration. +int __attribute__ ((ifunc ("_ZN5Klass13good_resolverEv"))) +Klass::good_magic (); + +Klass::Func* +Klass::good_resolver (void) +{ + MemFuncPtr mfp = &Klass::implementation; + + return reinterpret_cast<Func*>(mfp); +} + + +// Verify a warning for the unsafe declaration. + +int __attribute__ ((ifunc ("_ZN5Klass13iffy_resolverEv"))) +Klass::iffy_magic (); // { dg-message "resolver indirect function declared here" } + +void* +Klass::iffy_resolver (void) // { dg-warning ".ifunc. resolver for .int Klass::iffy_magic\\(\\). should return .int \\(\\*\\)\\(Klass\\*\\)." } +{ + MemFuncPtr mfp = &Klass::implementation; + + return reinterpret_cast<void*>(mfp); +} + + +// Verify an error for an incompatible declaration. + +const char* __attribute__ ((ifunc ("_ZN5Klass12bad_resolverEv"))) +Klass::bad_magic (); // { dg-message "resolver indirect function declared here" } Klass::MemFuncPtr -Klass::resolver (void) // { dg-message "aliased declaration here" } +Klass::bad_resolver (void) // { dg-error ".ifunc. resolver for .const char\\* Klass::bad_magic\\(\\). must return .const char\\* \\(\\*\\)\\(Klass\\*\\)." } { return &Klass::implementation; } |