// RUN: %clang_cc1 -std=c++23 -verify %s

void test_consteval() {
  if consteval ({(void)1;});  // expected-error {{expected { after consteval}}
  if consteval (void) 0; // expected-error {{expected { after consteval}}
  if consteval {
    (void)0;
  } else (void)0; // expected-error {{expected { after else}}

  static_assert([] {
    if consteval {
      return 0;
    }
    return 1;
  }() == 0);

  static_assert([] {
    if consteval {
      return 0;
    } else {
      return 1;
    }
  }() == 0);

  static_assert([] {
    if !consteval {
      return 0;
    } else {
      return 1;
    }
  }() == 1);

  static_assert([] {
    if not consteval {
      return 0;
    }
    return 1;
  }() == 1);

  if consteval [[likely]] { // expected-warning {{attribute 'likely' has no effect when annotating an 'if consteval' statement}}\
                            // expected-note 2{{annotating the 'if consteval' statement here}}


  }
  else [[unlikely]] { // expected-warning {{attribute 'unlikely' has no effect when annotating an 'if consteval' statement}}

  }

}

void test_consteval_jumps() {
  if consteval { // expected-note 4{{jump enters controlled statement of consteval if}}
    goto a;
    goto b; // expected-error {{cannot jump from this goto statement to its label}}
  a:;
  } else {
    goto b;
    goto a; // expected-error {{cannot jump from this goto statement to its label}}
  b:;
  }
  goto a; // expected-error {{cannot jump from this goto statement to its label}}
  goto b; // expected-error {{cannot jump from this goto statement to its label}}
}

void test_consteval_switch() {
  int x = 42;
  switch (x) {
    if consteval { // expected-note 2{{jump enters controlled statement of consteval if}}
    case 1:;       // expected-error {{cannot jump from switch statement to this case label}}
    default:;      // expected-error {{cannot jump from switch statement to this case label}}
    } else {
    }
  }
  switch (x) {
    if consteval { // expected-note 2{{jump enters controlled statement of consteval if}}
    } else {
    case 2:;  // expected-error {{cannot jump from switch statement to this case label}}
    default:; // expected-error {{cannot jump from switch statement to this case label}}
    }
  }
}

consteval int f(int i) { return i; }
constexpr int g(int i) {
  if consteval {
    return f(i);
  } else {
    return 42;
  }
}
static_assert(g(10) == 10);

constexpr int h(int i) { // expected-note {{declared here}}
  if !consteval {
    return f(i); // expected-error {{call to consteval function 'f' is not a constant expression}}\
                     // expected-note  {{cannot be used in a constant expression}}
  }
  return 0;
}

consteval void warn_in_consteval() {
  if consteval { // expected-warning {{consteval if is always true in an immediate context}}
    if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
  }
}

constexpr void warn_in_consteval2() {
  if consteval {
    if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
  }
}

auto y = []() consteval {
  if consteval { // expected-warning {{consteval if is always true in an immediate context}}
    if consteval {} // expected-warning {{consteval if is always true in an immediate context}}
  }
};

namespace test_transform {
int f(auto n) {
  if consteval {
    n.foo; //expected-error {{no member named}}
  }
  else {
  }

  if !consteval {
    n.foo; //expected-error {{no member named}}
  }
  else {
  }

  return 0;
}

constexpr int g(auto n) {
  if consteval {
  }
  else {
    n.foo; //expected-error {{no member named}}
  }

  if !consteval {
  }
  else {
     n.foo; //expected-error {{no member named}}
  }

  return 0;
}

struct S {};
void test() {
  f(S{}); //expected-note {{in instantiation}}
  g(S{}); //expected-note {{in instantiation}}
}

}
