/* { dg-options "-fgnu89-inline" } */

extern void abort(void);
extern void exit(int);

__attribute__((externally_visible)) int global;
int func(void);

/* These must fail.  */
int bad0(void) { return __builtin_constant_p(global); }
int bad1(void) { return __builtin_constant_p(global++); }
inline int bad2(int x) { return __builtin_constant_p(x++); }
inline int bad3(int x) { return __builtin_constant_p(x); }
inline int bad4(const char *x) { return __builtin_constant_p(x); }
int bad5(void) { return bad2(1); }
inline int bad6(int x) { return __builtin_constant_p(x + 1); }
int bad7(void) { return __builtin_constant_p(func()); }
int bad8(void) {
    char buf[10];
    return __builtin_constant_p(buf);
}
int bad9(const char *x) { return __builtin_constant_p(x[123456]); }
int bad10(void) { return __builtin_constant_p(&global); }

/* These must pass, or we've broken gcc2 functionality.  */
int good0(void) { return __builtin_constant_p(1); }
int good1(void) { return __builtin_constant_p("hi"); }
int good2(void) { return __builtin_constant_p((1234 + 45) & ~7); }

/* These are extensions to gcc2.  Failure indicates an optimization
   regression.  */
int opt0(void) { return bad3(1); }
int opt1(void) { return bad6(1); }
int opt2(void) { return __builtin_constant_p("hi"[0]); }

/*
 * Opt3 is known to fail.  It is one of the important cases that glibc
 * was interested in though, so keep this around as a reminder.
 *
 * The solution is to add bits to recover bytes from constant pool
 * elements given nothing but a constant pool label and an offset.
 * When we can do that, and we can simplify strlen after the fact,
 * then we can enable recognition of constant pool labels as constants.
 */

/* int opt3(void) { return bad4("hi"); } */


/* Call through tables so -finline-functions can't screw with us.  */
int (*volatile bad_t0[])(void) = {
    bad0, bad1, bad5, bad7, bad8, bad10};

int (*volatile bad_t1[])(int x) = {
    bad2, bad3, bad6};

int (*volatile bad_t2[])(const char *x) = {
    bad4, bad9};

int (*volatile good_t0[])(void) = {
    good0, good1, good2};

int (*volatile opt_t0[])(void) = {
    opt0, opt1, opt2 /* , opt3 */
};

#define N(arr) (sizeof(arr)/sizeof(*arr))

int main() {
    int i;

    for (i = 0; i < N(bad_t0); ++i)
        if ((*bad_t0[i])())
            abort();

    for (i = 0; i < N(bad_t1); ++i)
        if ((*bad_t1[i])(1))
            abort();

    for (i = 0; i < N(bad_t2); ++i)
        if ((*bad_t2[i])("hi"))
            abort();

    for (i = 0; i < N(good_t0); ++i)
        if (!(*good_t0[i])())
            abort();

#if __OPTIMIZE__ >= 2
    for (i = 0; i < N(opt_t0); ++i)
        if (!(*opt_t0[i])())
            abort();
#endif

    exit(0);
}
