attr-noreturn.cpp 9.94 KB
// RUN: %clang_cc1 -fsyntax-only -verify %s

// Reachability tests have to come first because they get suppressed
// if any errors have occurred.
namespace test5 {
  struct A {
    __attribute__((noreturn)) void fail();
    void nofail();
  } a;

  int &test1() {
    a.nofail();
  } // expected-warning {{non-void function does not return a value}}

  int &test2() {
    a.fail();
  }
}

namespace destructor_tests {
  __attribute__((noreturn)) void fail();

  struct A {
    ~A() __attribute__((noreturn)) { fail(); }
  };
  struct B {
    B() {}
    ~B() __attribute__((noreturn)) { fail(); }
  };
  struct C : A {};
  struct D : B {};
  struct E : virtual A {};
  struct F : A, virtual B {};
  struct G : E {};
  struct H : virtual D {};
  struct I : A {};
  struct J : I {};
  struct K : virtual A {};
  struct L : K {};
  struct M : virtual C {};
  struct N : M {};
  struct O { N n; };

  __attribute__((noreturn)) void test_1() { A a; }
  __attribute__((noreturn)) void test_2() { B b; }
  __attribute__((noreturn)) void test_3() { C c; }
  __attribute__((noreturn)) void test_4() { D d; }
  __attribute__((noreturn)) void test_5() { E e; }
  __attribute__((noreturn)) void test_6() { F f; }
  __attribute__((noreturn)) void test_7() { G g; }
  __attribute__((noreturn)) void test_8() { H h; }
  __attribute__((noreturn)) void test_9() { I i; }
  __attribute__((noreturn)) void test_10() { J j; }
  __attribute__((noreturn)) void test_11() { K k; }
  __attribute__((noreturn)) void test_12() { L l; }
  __attribute__((noreturn)) void test_13() { M m; }
  __attribute__((noreturn)) void test_14() { N n; }
  __attribute__((noreturn)) void test_15() { O o; }

  __attribute__((noreturn)) void test_16() { const A& a = A(); }
  __attribute__((noreturn)) void test_17() { const B& b = B(); }
  __attribute__((noreturn)) void test_18() { const C& c = C(); }
  __attribute__((noreturn)) void test_19() { const D& d = D(); }
  __attribute__((noreturn)) void test_20() { const E& e = E(); }
  __attribute__((noreturn)) void test_21() { const F& f = F(); }
  __attribute__((noreturn)) void test_22() { const G& g = G(); }
  __attribute__((noreturn)) void test_23() { const H& h = H(); }
  __attribute__((noreturn)) void test_24() { const I& i = I(); }
  __attribute__((noreturn)) void test_25() { const J& j = J(); }
  __attribute__((noreturn)) void test_26() { const K& k = K(); }
  __attribute__((noreturn)) void test_27() { const L& l = L(); }
  __attribute__((noreturn)) void test_28() { const M& m = M(); }
  __attribute__((noreturn)) void test_29() { const N& n = N(); }
  __attribute__((noreturn)) void test_30() { const O& o = O(); }

  struct AA {};
  struct BB { BB() {} ~BB() {} };
  struct CC : AA {};
  struct DD : BB {};
  struct EE : virtual AA {};
  struct FF : AA, virtual BB {};
  struct GG : EE {};
  struct HH : virtual DD {};
  struct II : AA {};
  struct JJ : II {};
  struct KK : virtual AA {};
  struct LL : KK {};
  struct MM : virtual CC {};
  struct NN : MM {};
  struct OO { NN n; };

  __attribute__((noreturn)) void test_31() {
    AA a;
    BB b;
    CC c;
    DD d;
    EE e;
    FF f;
    GG g;
    HH h;
    II i;
    JJ j;
    KK k;
    LL l;
    MM m;
    NN n;
    OO o;

    const AA& aa = AA();
    const BB& bb = BB();
    const CC& cc = CC();
    const DD& dd = DD();
    const EE& ee = EE();
    const FF& ff = FF();
    const GG& gg = GG();
    const HH& hh = HH();
    const II& ii = II();
    const JJ& jj = JJ();
    const KK& kk = KK();
    const LL& ll = LL();
    const MM& mm = MM();
    const NN& nn = NN();
    const OO& oo = OO();
  }  // expected-warning {{function declared 'noreturn' should not return}}

  struct P {
    ~P() __attribute__((noreturn)) { fail(); }
    void foo() {}
  };
  struct Q : P { };
  __attribute__((noreturn)) void test31() {
    P().foo();
  }
  __attribute__((noreturn)) void test32() {
    Q().foo();
  }

  struct R {
    A a[5];
  };
  __attribute__((noreturn)) void test33() {
    R r;
  }

  // FIXME: Code flow analysis does not preserve information about non-null
  // pointers, so it can't determine that this function is noreturn.
  __attribute__((noreturn)) void test34() {
    A *a = new A;
    delete a;
  }  // expected-warning {{function declared 'noreturn' should not return}}

  struct S {
    virtual ~S();
  };
  struct T : S {
    __attribute__((noreturn)) ~T();
  };

  // FIXME: Code flow analysis does not preserve information about non-null
  // pointers or derived class pointers,  so it can't determine that this
  // function is noreturn.
  __attribute__((noreturn)) void test35() {
    S *s = new T;
    delete s;
  }  // expected-warning {{function declared 'noreturn' should not return}}
}

// PR5620
void f0() __attribute__((__noreturn__));
void f1(void (*)());
void f2() { f1(f0); }

// Taking the address of a noreturn function
void test_f0a() {
  void (*fp)() = f0;
  void (*fp1)() __attribute__((noreturn)) = f0;
}

// Taking the address of an overloaded noreturn function 
void f0(int) __attribute__((__noreturn__));

void test_f0b() {
  void (*fp)() = f0;
  void (*fp1)() __attribute__((noreturn)) = f0;
}

// No-returned function pointers
typedef void (* noreturn_fp)() __attribute__((noreturn));

void f3(noreturn_fp); // expected-note{{candidate function}}

void test_f3() {
  f3(f0); // okay
  f3(f2); // expected-error{{no matching function for call}}
}


class xpto {
  int blah() __attribute__((noreturn));
};

int xpto::blah() {
  return 3; // expected-warning {{function 'blah' declared 'noreturn' should not return}}
}

// PR12948

namespace PR12948 {
  template<int>
  void foo() __attribute__((__noreturn__));

  template<int>
  void foo() {
    while (1) continue;
  }

  void bar() __attribute__((__noreturn__));

  void bar() {
    foo<0>();
  }


  void baz() __attribute__((__noreturn__));
  typedef void voidfn();
  voidfn baz;

  template<typename> void wibble()  __attribute__((__noreturn__));
  template<typename> voidfn wibble;
}

// PR15291
// Overload resolution per over.over should allow implicit noreturn adjustment.
namespace PR15291 {
  __attribute__((noreturn)) void foo(int) {}
  __attribute__((noreturn)) void foo(double) {}

  template <typename T>
  __attribute__((noreturn)) void bar(T) {}

  void baz(int) {}
  void baz(double) {}

  template <typename T>
  void qux(T) {}

  // expected-note@+5 {{candidate function template not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
  // expected-note@+4 {{candidate function template not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
  // expected-note@+3 {{candidate function template not viable: no overload of 'bar' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
  // expected-note@+2 {{candidate function template not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
  // expected-note@+1 {{candidate function template not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
  template <typename T> void accept_T(T) {}

  // expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'void (*)(int)' for 1st argument}}
  void accept_fptr(void (*f)(int)) {
    f(42);
  }

  // expected-note@+2 {{candidate function not viable: no overload of 'baz' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
  // expected-note@+1 {{candidate function not viable: no overload of 'qux' matching 'void (*)(int) __attribute__((noreturn))' for 1st argument}}
  void accept_noreturn_fptr(void __attribute__((noreturn)) (*f)(int)) {
    f(42);
  }

  typedef void (*fptr_t)(int);
  typedef void __attribute__((noreturn)) (*fptr_noreturn_t)(int);

  // expected-note@+1 {{candidate function not viable: no overload of 'bar' matching 'PR15291::fptr_t' (aka 'void (*)(int)') for 1st argument}}
  void accept_fptr_t(fptr_t f) {
    f(42);
  }

  // expected-note@+2 {{candidate function not viable: no overload of 'baz' matching 'PR15291::fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
  // expected-note@+1 {{candidate function not viable: no overload of 'qux' matching 'PR15291::fptr_noreturn_t' (aka 'void (*)(int) __attribute__((noreturn))') for 1st argument}}
  void accept_fptr_noreturn_t(fptr_noreturn_t f) {
    f(42);
  }

  // Stripping noreturn should work if everything else is correct.
  void strip_noreturn() {
    accept_fptr(foo);
    accept_fptr(bar<int>);
    accept_fptr(bar<double>); // expected-error {{no matching function for call to 'accept_fptr'}}

    accept_fptr_t(foo);
    accept_fptr_t(bar<int>);
    accept_fptr_t(bar<double>); // expected-error {{no matching function for call to 'accept_fptr_t'}}

    accept_T<void __attribute__((noreturn)) (*)(int)>(foo);
    accept_T<void __attribute__((noreturn)) (*)(int)>(bar<int>);
    accept_T<void __attribute__((noreturn)) (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}

    accept_T<void (*)(int)>(foo);
    accept_T<void (*)(int)>(bar<int>);
    accept_T<void (*)(int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}

    accept_T<void (int)>(foo);
    accept_T<void (int)>(bar<int>);
    accept_T<void (int)>(bar<double>); // expected-error {{no matching function for call to 'accept_T'}}
  }

  // Introducing noreturn should not work.
  void introduce_noreturn() {
    accept_noreturn_fptr(baz); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}
    accept_noreturn_fptr(qux<int>); // expected-error {{no matching function for call to 'accept_noreturn_fptr'}}

    accept_fptr_noreturn_t(baz); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}
    accept_fptr_noreturn_t(qux<int>); // expected-error {{no matching function for call to 'accept_fptr_noreturn_t'}}

    accept_T<void __attribute__((noreturn)) (*)(int)>(baz); // expected-error {{no matching function for call to 'accept_T'}}
    accept_T<void __attribute__((noreturn)) (*)(int)>(qux<int>); // expected-error {{no matching function for call to 'accept_T'}}
  }
}