/* { dg-do compile } */ /* { dg-options "-fstrub=strict" } */ /* { dg-require-effective-target strub } */ /* Check that impermissible (cross-strub-context) calls are reported. */ extern int __attribute__ ((__strub__ ("callable"))) xcallable (void); extern int __attribute__ ((__strub__ ("internal"))) xinternal (void); extern int __attribute__ ((__strub__ ("at-calls"))) xat_calls (void); extern int __attribute__ ((__strub__ ("disabled"))) xdisabled (void); int __attribute__ ((__strub__ ("callable"))) callable (void); int __attribute__ ((__strub__ ("internal"))) internal (void); int __attribute__ ((__strub__ ("at-calls"))) at_calls (void); int __attribute__ ((__strub__ ("disabled"))) disabled (void); int __attribute__ ((__strub__)) var; int var_user (void); static inline int __attribute__ ((__always_inline__, __strub__ ("callable"))) icallable (void); static inline int __attribute__ ((__always_inline__, __strub__ ("internal"))) iinternal (void); static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls"))) iat_calls (void); static inline int __attribute__ ((__always_inline__, __strub__ ("disabled"))) idisabled (void); static inline int __attribute__ ((__always_inline__)) ivar_user (void); static inline int __attribute__ ((__always_inline__, __strub__ ("callable"))) i_callable (void) { return 0; } static inline int __attribute__ ((__always_inline__, __strub__ ("internal"))) i_internal (void) { return var; } static inline int __attribute__ ((__always_inline__, __strub__ ("at-calls"))) i_at_calls (void) { return var; } static inline int __attribute__ ((__always_inline__, __strub__ ("disabled"))) i_disabled (void) { return 0; } static inline int __attribute__ ((__always_inline__)) i_var_user (void) { return var; } #define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \ do { \ ret += i ## ISEP ## at_calls (); \ ret += i ## ISEP ## internal (); \ ret += i ## ISEP ## var_user (); \ } while (0) #define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \ do { \ ret += internal (); \ ret += disabled (); \ ret += var_user (); \ \ ret += i ## ISEP ## disabled (); \ \ ret += xinternal (); \ ret += xdisabled (); \ } while (0) #define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \ do { \ ret += i ## ISEP ## callable (); \ \ ret += callable (); \ ret += at_calls (); \ \ ret += xat_calls (); \ ret += xcallable (); \ } while (0) /* Not a strub context, so it can call anything. Explicitly declared as callable even from within strub contexts. */ int __attribute__ ((__strub__ ("callable"))) callable (void) { int ret = 0; /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += iat_calls (); /* { dg-error "in non-.strub. context" } */ ret += iinternal (); /* { dg-error "in non-.strub. context" } */ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */ #endif CALLS_GOOD_FOR_EITHER_CONTEXT(); CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); return ret; } /* Internal strubbing means the body is a strub context, so it can only call strub functions, and it's not itself callable from strub functions. */ int __attribute__ ((__strub__ ("internal"))) internal (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(); CALLS_GOOD_FOR_EITHER_CONTEXT(); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += idisabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; } int __attribute__ ((__strub__ ("at-calls"))) at_calls (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(); CALLS_GOOD_FOR_EITHER_CONTEXT(); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += idisabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; } int __attribute__ ((__strub__ ("disabled"))) disabled () { int ret = 0; /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += iat_calls (); /* { dg-error "in non-.strub. context" } */ ret += iinternal (); /* { dg-error "in non-.strub. context" } */ ret += ivar_user (); /* { dg-error "in non-.strub. context" } */ #endif CALLS_GOOD_FOR_EITHER_CONTEXT(); CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); return ret; } int var_user (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(); CALLS_GOOD_FOR_EITHER_CONTEXT(); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += idisabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; } int icallable (void) { int ret = 0; /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */ ret += i_internal (); /* { dg-error "in non-.strub. context" } */ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */ #endif CALLS_GOOD_FOR_EITHER_CONTEXT(_); CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); return ret; } int iinternal (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(_); CALLS_GOOD_FOR_EITHER_CONTEXT(_); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += i_disabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; } int __attribute__ ((__always_inline__, __strub__ ("at-calls"))) iat_calls (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(_); CALLS_GOOD_FOR_EITHER_CONTEXT(_); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += i_disabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; } int idisabled () { int ret = 0; /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */ ret += i_internal (); /* { dg-error "in non-.strub. context" } */ ret += i_var_user (); /* { dg-error "in non-.strub. context" } */ #endif CALLS_GOOD_FOR_EITHER_CONTEXT(_); CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); return ret; } int ivar_user (void) { int ret = var; CALLS_GOOD_FOR_STRUB_CONTEXT(_); CALLS_GOOD_FOR_EITHER_CONTEXT(_); /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ #if !OMIT_IMPERMISSIBLE_CALLS ret += internal (); /* { dg-error "in .strub. context" } */ ret += disabled (); /* { dg-error "in .strub. context" } */ ret += var_user (); /* { dg-error "in .strub. context" } */ ret += i_disabled (); /* { dg-error "in .strub. context" } */ ret += xinternal (); /* { dg-error "in .strub. context" } */ ret += xdisabled (); /* { dg-error "in .strub. context" } */ #endif return ret; }