aboutsummaryrefslogtreecommitdiff
path: root/clang/test/AST/ByteCode/builtin-constant-p.cpp
blob: 315a907949c34ee9693a4a562f53ffdfd5814c01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// RUN: %clang_cc1 -std=c++20 -verify=expected,both %s -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 -std=c++20 -verify=ref,both      %s

using intptr_t = __INTPTR_TYPE__;

static_assert(__builtin_constant_p(12), "");
static_assert(__builtin_constant_p(1.0), "");

constexpr int I = 100;
static_assert(__builtin_constant_p(I), "");
static_assert(__builtin_constant_p(I + 10), "");
static_assert(__builtin_constant_p(I + 10.0), "");
static_assert(__builtin_constant_p(nullptr), "");
static_assert(__builtin_constant_p(&I), ""); // both-error {{failed due to requirement}}
static_assert(__builtin_constant_p((void)I), ""); // both-error {{failed due to requirement}}

extern int z;
constexpr int foo(int &a) {
  return __builtin_constant_p(a);
}
static_assert(!foo(z));

static_assert(__builtin_constant_p(__builtin_constant_p(1)));

constexpr bool nested(int& a) {
  return __builtin_constant_p(__builtin_constant_p(a));
}
static_assert(nested(z));

constexpr bool Local() {
  int z = 10;
  return __builtin_constant_p(z);
}
static_assert(Local());

constexpr bool Local2() {
  int z = 10;
  return __builtin_constant_p(&z);
}
static_assert(!Local2());

constexpr bool Parameter(int a) {
  return __builtin_constant_p(a);
}
static_assert(Parameter(10));

constexpr bool InvalidLocal() {
  int *z;
  {
    int b = 10;
    z = &b;
  }
  return __builtin_constant_p(z);
}
static_assert(!InvalidLocal());

template<typename T> constexpr bool bcp(T t) {
  return __builtin_constant_p(t);
}

constexpr intptr_t ptr_to_int(const void *p) {
  return __builtin_constant_p(1) ? (intptr_t)p : (intptr_t)p;
}

static_assert(bcp(ptr_to_int("foo")));

constexpr bool AndFold(const int &a, const int &b) {
  return __builtin_constant_p(a && b);
}

static_assert(AndFold(10, 20));
static_assert(!AndFold(z, 10));
static_assert(!AndFold(10, z));


struct F {
  int a;
};

constexpr F f{12};
static_assert(__builtin_constant_p(f.a));

constexpr bool Member() {
  F f;
  return __builtin_constant_p(f.a);
}
static_assert(!Member());

constexpr bool Discard() {
  (void)__builtin_constant_p(10);
  return true;
}
static_assert(Discard());

static_assert(__builtin_constant_p((int*)123));

constexpr void func() {}
static_assert(!__builtin_constant_p(func));

/// This is from SemaCXX/builtin-constant-p and GCC agrees with the bytecode interpreter.
constexpr int mutate1() {
  int n = 1;
  int m = __builtin_constant_p(++n);
  return n * 10 + m;
}
static_assert(mutate1() == 21); // ref-error {{static assertion failed}} \
                                // ref-note {{evaluates to '10 == 21'}}

/// Similar for this. GCC agrees with the bytecode interpreter.
constexpr int mutate_param(bool mutate, int &param) {
  mutate = mutate; // Mutation of internal state is OK
  if (mutate)
    ++param;
  return param;
}
constexpr int mutate6(bool mutate) {
  int n = 1;
  int m = __builtin_constant_p(mutate_param(mutate, n));
  return n * 10 + m;
}
static_assert(mutate6(false) == 11);
static_assert(mutate6(true) == 21); // ref-error {{static assertion failed}} \
                                    // ref-note {{evaluates to '10 == 21'}}

#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
void g() {
  /// f will be revisited when evaluating the static_assert, since it's
  /// a local variable. But it should be visited in a non-constant context.
  const float f = __builtin_is_constant_evaluated();
  static_assert(fold(f == 0.0f));
}

void test17(void) {
#define ASSERT(...) { enum { folded = (__VA_ARGS__) }; int arr[folded ? 1 : -1]; }
#define T(...) ASSERT(__builtin_constant_p(__VA_ARGS__))
#define F(...) ASSERT(!__builtin_constant_p(__VA_ARGS__))

  T(3i + 5);
  T("string literal");
  F("string literal" + 1); // both-warning {{adding}} \
                           // both-note {{use array indexing}}
}

/// FIXME
static void foo(int i) __attribute__((__diagnose_if__(!__builtin_constant_p(i), "not constant", "error"))) // expected-note {{from}}
{
}
static void bar(int i) {
  foo(15); // expected-error {{not constant}}
}