blob: 9da120f61564598ab94622201fed45182d45e79d [file] [log] [blame]
/* { 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;
}