// RUN: %clang %s -fsyntax-only -Wignored-qualifiers -Wreturn-type -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value

// clang emits the following warning by default.
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the 
// following warning.
int t14() {
  return; // expected-warning {{non-void function 't14' should return a value}}
}

void t15() {
  return 1; // expected-warning {{void function 't15' should not return a value}}
}

int unknown();

void test0() {
}

int test1() {
} // expected-warning {{control reaches end of non-void function}}

int test2() {
  a: goto a;
}

int test3() {
  goto a;
  a: ;
} // expected-warning {{control reaches end of non-void function}}


void halt() {
  a: goto a;
}

void halt2() __attribute__((noreturn));

int test4() {
  halt2();
}

int test5() {
  halt2(), (void)1;
}

int test6() {
  1, halt2();
}

int j;
int unknown_nohalt() {
  return j;
}

int test7() {
  unknown();
} // expected-warning {{control reaches end of non-void function}}

int test8() {
  (void)(1 + unknown());
} // expected-warning {{control reaches end of non-void function}}

int halt3() __attribute__((noreturn));

int test9() {
  (void)(halt3() + unknown());
}

int test10() {
  (void)(unknown() || halt3());
} // expected-warning {{control may reach end of non-void function}}

int test11() {
  (void)(unknown() && halt3());
} // expected-warning {{control may reach end of non-void function}}

int test12() {
  (void)(halt3() || unknown());
}

int test13() {
  (void)(halt3() && unknown());
}

int test14() {
  (void)(1 || unknown());
} // expected-warning {{control reaches end of non-void function}}

int test15() {
  (void)(0 || unknown());
} // expected-warning {{control reaches end of non-void function}}

int test16() {
  (void)(0 && unknown());
} // expected-warning {{control reaches end of non-void function}}

int test17() {
  (void)(1 && unknown());
} // expected-warning {{control reaches end of non-void function}}

int test18() {
  (void)(unknown_nohalt() && halt3());
} // expected-warning {{control may reach end of non-void function}}

int test19() {
  (void)(unknown_nohalt() && unknown());
} // expected-warning {{control reaches end of non-void function}}

int test20() {
  int i;
  if (i)
    return 0;
  else if (0)
    return 2;
} // expected-warning {{control may reach end of non-void function}}

int test21() {
  int i;
  if (i)
    return 0;
  else if (1)
    return 2;
}

int test22() {
  int i;
  switch (i) default: ;
} // expected-warning {{control reaches end of non-void function}}

int test23() {
  int i;
  switch (i) {
  case 0:
    return 0;
  case 2:
    return 2;
  }
} // expected-warning {{control may reach end of non-void function}}

int test24() {
  int i;
  switch (i) {
    case 0:
    return 0;
  case 2:
    return 2;
  default:
    return -1;
  }
}

int test25() {
  1 ? halt3() : unknown();
}

int test26() {
  0 ? halt3() : unknown();
} // expected-warning {{control reaches end of non-void function}}

int j;
void (*fptr)() __attribute__((noreturn));
int test27() {
  switch (j) {
  case 1:
    do { } while (1);
    break;
  case 2:
    for (;;) ;
    break;
  case 3:
    for (;1;) ;
    for (;0;) {
      goto done;
    }
    return 1;
  case 4:    
    while (0) { goto done; }
    return 1;
  case 5:
    while (1) { return 1; }
    break;
  case 6:
    fptr();
    break;
  default:
    return 1;
  }
  done: ;
}

// PR4624
void test28() __attribute__((noreturn));
void test28(x) { while (1) { } }

void exit(int);
int test29() {
  exit(1);
}

#include <setjmp.h>
jmp_buf test30_j;
int test30() {
  if (j)
    longjmp(test30_j, 1);
  else
#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
    longjmp(test30_j, 2);
#else
    _longjmp(test30_j, 1);
#endif
}

typedef void test31_t(int status);
void test31(test31_t *callback __attribute__((noreturn)));

void test32() {
  ^ (void) { while (1) { } }();
  ^ (void) { if (j) while (1) { } }();
  while (1) { }
}

void test33() {
  if (j) while (1) { }
}

// Test that 'static inline' functions are only analyzed for CFG-based warnings
// when they are used.
static inline int si_has_missing_return() {} // expected-warning{{control reaches end of non-void function}}
static inline int si_has_missing_return_2() {}; // expected-warning{{control reaches end of non-void function}}
static inline int si_forward();
static inline int si_has_missing_return_3(int x) {
  if (x)
   return si_has_missing_return_3(x+1);
} // expected-warning{{control may reach end of non-void function}}

int test_static_inline(int x) {
  si_forward();
  return x ? si_has_missing_return_2() : si_has_missing_return_3(x);
}
static inline int si_forward() {} // expected-warning{{control reaches end of non-void function}}

// Test warnings on ignored qualifiers on return types.
const int ignored_c_quals(); // expected-warning{{'const' type qualifier on return type has no effect}}
const volatile int ignored_cv_quals(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
char* const volatile restrict ignored_cvr_quals(); // expected-warning{{'const volatile restrict' type qualifiers on return type have no effect}}

// Test that for switch(enum) that if the switch statement covers all the cases
// that we don't consider that for -Wreturn-type.
enum Cases { C1, C2, C3, C4 };
int test_enum_cases(enum Cases C) {
  switch (C) {
  case C1: return 1;
  case C2: return 2;
  case C4: return 3;
  case C3: return 4;
  }
} // no-warning
