blob: 5bb48ffc54dd5af74f0d01519e082af6714fa174 [file] [log] [blame]
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify %s
// RUN: %clang_cc1 -verify=ref %s
constexpr void doNothing() {}
constexpr int gimme5() {
doNothing();
return 5;
}
static_assert(gimme5() == 5, "");
template<typename T> constexpr T identity(T t) {
static_assert(true, "");
return t;
}
static_assert(identity(true), "");
static_assert(identity(true), ""); /// Compiled bytecode should be cached
static_assert(!identity(false), "");
template<typename A, typename B>
constexpr bool sameSize() {
static_assert(sizeof(A) == sizeof(B), ""); // expected-error {{static assertion failed}} \
// ref-error {{static assertion failed}} \
// expected-note {{evaluates to}} \
// ref-note {{evaluates to}}
return true;
}
static_assert(sameSize<int, int>(), "");
static_assert(sameSize<unsigned int, int>(), "");
static_assert(sameSize<char, long>(), ""); // expected-note {{in instantiation of function template specialization}} \
// ref-note {{in instantiation of function template specialization}}
constexpr auto add(int a, int b) -> int {
return identity(a) + identity(b);
}
constexpr int sub(int a, int b) {
return a - b;
}
static_assert(sub(5, 2) == 3, "");
static_assert(sub(0, 5) == -5, "");
constexpr int norm(int n) {
if (n >= 0) {
return identity(n);
}
return -identity(n);
}
static_assert(norm(5) == norm(-5), "");
constexpr int square(int n) {
return norm(n) * norm(n);
}
static_assert(square(2) == 4, "");
constexpr int add_second(int a, int b, bool doAdd = true) {
if (doAdd)
return a + b;
return a;
}
static_assert(add_second(10, 3, true) == 13, "");
static_assert(add_second(10, 3) == 13, "");
static_assert(add_second(300, -20, false) == 300, "");
constexpr int sub(int a, int b, int c) {
return a - b - c;
}
static_assert(sub(10, 8, 2) == 0, "");
constexpr int recursion(int i) {
doNothing();
i = i - 1;
if (i == 0)
return identity(0);
return recursion(i);
}
static_assert(recursion(10) == 0, "");
template<int N = 5>
constexpr decltype(N) getNum() {
return N;
}
static_assert(getNum<-2>() == -2, "");
static_assert(getNum<10>() == 10, "");
static_assert(getNum() == 5, "");
constexpr int f(); // expected-note {{declared here}} \
// ref-note {{declared here}}
static_assert(f() == 5, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{undefined function 'f'}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{undefined function 'f'}}
constexpr int a() {
return f();
}
constexpr int f() {
return 5;
}
static_assert(a() == 5, "");
constexpr int invalid() {
// Invalid expression in visit().
while(huh) {} // expected-error {{use of undeclared identifier}} \
// ref-error {{use of undeclared identifier}}
return 0;
}
constexpr void invalid2() {
int i = 0;
// Invalid expression in discard().
huh(); // expected-error {{use of undeclared identifier}} \
// ref-error {{use of undeclared identifier}}
}
namespace FunctionPointers {
constexpr int add(int a, int b) {
return a + b;
}
struct S { int a; };
constexpr S getS() {
return S{12};
}
constexpr int applyBinOp(int a, int b, int (*op)(int, int)) {
return op(a, b);
}
static_assert(applyBinOp(1, 2, add) == 3, "");
constexpr int ignoreReturnValue() {
int (*foo)(int, int) = add;
foo(1, 2);
return 1;
}
static_assert(ignoreReturnValue() == 1, "");
constexpr int createS(S (*gimme)()) {
gimme(); // Ignored return value
return gimme().a;
}
static_assert(createS(getS) == 12, "");
namespace FunctionReturnType {
typedef int (*ptr)(int*);
typedef ptr (*pm)();
constexpr int fun1(int* y) {
return *y + 10;
}
constexpr ptr fun() {
return &fun1;
}
static_assert(fun() == nullptr, ""); // expected-error {{static assertion failed}} \
// ref-error {{static assertion failed}}
constexpr int foo() {
int (*f)(int *) = fun();
int m = 0;
m = f(&m);
return m;
}
static_assert(foo() == 10, "");
struct S {
int i;
void (*fp)();
};
constexpr S s{ 12 };
static_assert(s.fp == nullptr, ""); // zero-initialized function pointer.
}
namespace Comparison {
void f(), g();
constexpr void (*pf)() = &f, (*pg)() = &g;
constexpr bool u13 = pf < pg; // ref-warning {{ordered comparison of function pointers}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{comparison between '&f' and '&g' has unspecified value}} \
// expected-warning {{ordered comparison of function pointers}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{comparison between '&f' and '&g' has unspecified value}}
constexpr bool u14 = pf < (void(*)())nullptr; // ref-warning {{ordered comparison of function pointers}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{comparison between '&f' and 'nullptr' has unspecified value}} \
// expected-warning {{ordered comparison of function pointers}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{comparison between '&f' and 'nullptr' has unspecified value}}
static_assert(pf != pg, "");
static_assert(pf == &f, "");
static_assert(pg == &g, "");
}
}
struct F {
constexpr bool ok() const {
return okRecurse();
}
constexpr bool okRecurse() const {
return true;
}
};
struct BodylessMemberFunction {
constexpr int first() const {
return second();
}
constexpr int second() const {
return 1;
}
};
constexpr int nyd(int m);
constexpr int doit() { return nyd(10); }
constexpr int nyd(int m) { return m; }
static_assert(doit() == 10, "");
namespace InvalidCall {
struct S {
constexpr int a() const { // expected-error {{never produces a constant expression}} \
// ref-error {{never produces a constant expression}}
return 1 / 0; // expected-note 2{{division by zero}} \
// expected-warning {{is undefined}} \
// ref-note 2{{division by zero}} \
// ref-warning {{is undefined}}
}
};
constexpr S s;
static_assert(s.a() == 1, ""); // expected-error {{not an integral constant expression}} \
// expected-note {{in call to}} \
// ref-error {{not an integral constant expression}} \
// ref-note {{in call to}}
/// This used to cause an assertion failure in the new constant interpreter.
constexpr void func(); // expected-note {{declared here}} \
// ref-note {{declared here}}
struct SS {
constexpr SS() { func(); } // expected-note {{undefined function }} \
// ref-note {{undefined function}}
};
constexpr SS ss; // expected-error {{must be initialized by a constant expression}} \
// expected-note {{in call to 'SS()'}} \
// ref-error {{must be initialized by a constant expression}} \
// ref-note {{in call to 'SS()'}}
}