Add -Wunused-local-typedef, a warning that finds unused local typedefs.
The warning warns on TypedefNameDecls -- typedefs and C++11 using aliases --
that are !isReferenced(). Since the isReferenced() bit on TypedefNameDecls
wasn't used for anything before this warning it wasn't always set correctly,
so this patch also adds a few missing MarkAnyDeclReferenced() calls in
various places for TypedefNameDecls.
This is made a bit complicated due to local typedefs possibly being used only
after their local scope has closed. Consider:
template <class T>
void template_fun(T t) {
typename T::Foo s3foo; // YYY
(void)s3foo;
}
void template_fun_user() {
struct Local {
typedef int Foo; // XXX
} p;
template_fun(p);
}
Here the typedef in XXX is only used at end-of-translation unit, when YYY in
template_fun() gets instantiated. To handle this, typedefs that are unused when
their scope exits are added to a set of potentially unused typedefs, and that
set gets checked at end-of-TU. Typedefs that are still unused at that point then
get warned on. There's also serialization code for this set, so that the
warning works with precompiled headers and modules. For modules, the warning
is emitted when the module is built, for precompiled headers each time the
header gets used.
Finally, consider a function using C++14 auto return types to return a local
type defined in a header:
auto f() {
struct S { typedef int a; };
return S();
}
Here, the typedef escapes its local scope and could be used by only some
translation units including the header. To not warn on this, add a
RecursiveASTVisitor that marks all delcs on local types returned from auto
functions as referenced. (Except if it's a function with internal linkage, or
the decls are private and the local type has no friends -- in these cases, it
_is_ safe to warn.)
Several of the included testcases (most of the interesting ones) were provided
by Richard Smith.
(gcc's spelling -Wunused-local-typedefs is supported as an alias for this
warning.)
llvm-svn: 217298
2014-09-06 09:25:55 +08:00
|
|
|
// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall -Wno-unused-local-typedefs %s
|
2011-06-12 01:19:42 +08:00
|
|
|
|
|
|
|
template<bool b> struct ExceptionIf { static int f(); };
|
|
|
|
template<> struct ExceptionIf<false> { typedef int f; };
|
|
|
|
|
|
|
|
// The exception specification of a defaulted default constructor depends on
|
|
|
|
// the contents of in-class member initializers. However, the in-class member
|
|
|
|
// initializers can depend on the exception specification of the constructor,
|
|
|
|
// since the class is considered complete within them. We reject any such cases.
|
|
|
|
namespace InClassInitializers {
|
|
|
|
// Noexcept::Noexcept() is implicitly declared as noexcept(false), because it
|
|
|
|
// directly invokes ThrowSomething(). However...
|
|
|
|
//
|
|
|
|
// If noexcept(Noexcept()) is false, then Noexcept() is a constant expression,
|
|
|
|
// so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then
|
|
|
|
// Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept())
|
|
|
|
// is false.
|
|
|
|
bool ThrowSomething() noexcept(false);
|
2017-01-07 08:48:55 +08:00
|
|
|
struct ConstExpr {
|
|
|
|
bool b = // expected-note {{declared here}}
|
|
|
|
noexcept(ConstExpr()) && ThrowSomething(); // expected-error {{default member initializer for 'b' needed}}
|
2011-06-12 01:19:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Much more obviously broken: we can't parse the initializer without already
|
|
|
|
// knowing whether it produces a noexcept expression.
|
2017-01-07 08:48:55 +08:00
|
|
|
struct TemplateArg {
|
|
|
|
int n = // expected-note {{declared here}}
|
|
|
|
ExceptionIf<noexcept(TemplateArg())>::f(); // expected-error {{default member initializer for 'n' needed}}
|
2011-06-12 01:19:42 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// And within a nested class.
|
2017-01-07 08:48:55 +08:00
|
|
|
struct Nested {
|
|
|
|
struct Inner {
|
2016-11-23 06:55:12 +08:00
|
|
|
int n = // expected-note {{declared here}}
|
2017-01-07 08:48:55 +08:00
|
|
|
ExceptionIf<noexcept(Nested())>::f();
|
|
|
|
} inner; // expected-error {{default member initializer for 'n' needed}}
|
2011-06-12 01:19:42 +08:00
|
|
|
};
|
Final piece of core issue 1330: delay computing the exception specification of
a defaulted special member function until the exception specification is needed
(using the same criteria used for the delayed instantiation of exception
specifications for function temploids).
EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
resolve the exception specification.
This is enabled for all C++ modes: it's a little faster in the case where the
exception specification isn't used, allows our C++11-in-C++98 extensions to
work, and is still correct for C++98, since in that mode the computation of the
exception specification can't fail.
The diagnostics here aren't great (in particular, we should include implicit
evaluation of exception specifications for defaulted special members in the
template instantiation backtraces), but they're not much worse than before.
Our approach to the problem of cycles between in-class initializers and the
exception specification for a defaulted default constructor is modified a
little by this change -- we now reject any odr-use of a defaulted default
constructor if that constructor uses an in-class initializer and the use is in
an in-class initialzer which is declared lexically earlier. This is a closer
approximation to the current draft solution in core issue 1351, but isn't an
exact match (but the current draft wording isn't reasonable, so that's to be
expected).
llvm-svn: 160847
2012-07-27 12:22:15 +08:00
|
|
|
|
2017-01-07 08:48:55 +08:00
|
|
|
struct Nested2 {
|
Final piece of core issue 1330: delay computing the exception specification of
a defaulted special member function until the exception specification is needed
(using the same criteria used for the delayed instantiation of exception
specifications for function temploids).
EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
resolve the exception specification.
This is enabled for all C++ modes: it's a little faster in the case where the
exception specification isn't used, allows our C++11-in-C++98 extensions to
work, and is still correct for C++98, since in that mode the computation of the
exception specification can't fail.
The diagnostics here aren't great (in particular, we should include implicit
evaluation of exception specifications for defaulted special members in the
template instantiation backtraces), but they're not much worse than before.
Our approach to the problem of cycles between in-class initializers and the
exception specification for a defaulted default constructor is modified a
little by this change -- we now reject any odr-use of a defaulted default
constructor if that constructor uses an in-class initializer and the use is in
an in-class initialzer which is declared lexically earlier. This is a closer
approximation to the current draft solution in core issue 1351, but isn't an
exact match (but the current draft wording isn't reasonable, so that's to be
expected).
llvm-svn: 160847
2012-07-27 12:22:15 +08:00
|
|
|
struct Inner;
|
2017-01-07 08:48:55 +08:00
|
|
|
int n = Inner().n; // expected-error {{initializer for 'n' needed}}
|
|
|
|
struct Inner {
|
|
|
|
int n = ExceptionIf<noexcept(Nested2())>::f(); // expected-note {{declared here}}
|
|
|
|
} inner;
|
Final piece of core issue 1330: delay computing the exception specification of
a defaulted special member function until the exception specification is needed
(using the same criteria used for the delayed instantiation of exception
specifications for function temploids).
EST_Delayed is now EST_Unevaluated (using 1330's terminology), and, like
EST_Uninstantiated, carries a pointer to the FunctionDecl which will be used to
resolve the exception specification.
This is enabled for all C++ modes: it's a little faster in the case where the
exception specification isn't used, allows our C++11-in-C++98 extensions to
work, and is still correct for C++98, since in that mode the computation of the
exception specification can't fail.
The diagnostics here aren't great (in particular, we should include implicit
evaluation of exception specifications for defaulted special members in the
template instantiation backtraces), but they're not much worse than before.
Our approach to the problem of cycles between in-class initializers and the
exception specification for a defaulted default constructor is modified a
little by this change -- we now reject any odr-use of a defaulted default
constructor if that constructor uses an in-class initializer and the use is in
an in-class initialzer which is declared lexically earlier. This is a closer
approximation to the current draft solution in core issue 1351, but isn't an
exact match (but the current draft wording isn't reasonable, so that's to be
expected).
llvm-svn: 160847
2012-07-27 12:22:15 +08:00
|
|
|
};
|
2011-06-12 01:19:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace ExceptionSpecification {
|
2014-11-14 04:01:57 +08:00
|
|
|
// FIXME: This diagnostic is quite useless; we should indicate whose
|
|
|
|
// exception specification we were looking for and why.
|
|
|
|
struct Nested {
|
2011-06-12 01:19:42 +08:00
|
|
|
struct T {
|
2014-11-14 04:01:57 +08:00
|
|
|
T() noexcept(!noexcept(Nested()));
|
|
|
|
} t; // expected-error{{exception specification is not available until end of class definition}}
|
2011-06-12 01:19:42 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace DefaultArgument {
|
2012-03-31 04:53:28 +08:00
|
|
|
struct Default {
|
2011-06-12 01:19:42 +08:00
|
|
|
struct T {
|
2012-02-16 03:33:52 +08:00
|
|
|
T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}}
|
2012-03-31 04:53:28 +08:00
|
|
|
} t; // expected-note {{has no default constructor}}
|
2011-06-12 01:19:42 +08:00
|
|
|
};
|
|
|
|
}
|
2012-04-22 02:42:51 +08:00
|
|
|
|
|
|
|
namespace ImplicitDtorExceptionSpec {
|
|
|
|
struct A {
|
|
|
|
virtual ~A();
|
|
|
|
|
|
|
|
struct Inner {
|
|
|
|
~Inner() throw();
|
|
|
|
};
|
|
|
|
Inner inner;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B {
|
|
|
|
virtual ~B() {} // expected-note {{here}}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct C : B {
|
|
|
|
virtual ~C() {}
|
|
|
|
A a;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct D : B {
|
|
|
|
~D(); // expected-error {{more lax than base}}
|
|
|
|
struct E {
|
|
|
|
~E();
|
|
|
|
struct F {
|
|
|
|
~F() throw(A);
|
|
|
|
} f;
|
|
|
|
} e;
|
|
|
|
};
|
|
|
|
}
|
C++ DR1611, 1658, 2180: implement "potentially constructed subobject" rules for special member functions.
Essentially, as a base class constructor does not construct virtual bases, such
a constructor for an abstract class does not need the corresponding base class
construction to be valid, and likewise for destructors.
This creates an awkward situation: clang will sometimes generate references to
the complete object and deleting destructors for an abstract class (it puts
them in the construction vtable for a derived class). But we can't generate a
"correct" version of these because we can't generate references to base class
constructors any more (if they're template specializations, say, we might not
have instantiated them and can't assume any other TU will emit a copy).
Fortunately, we don't need to, since no correct program can ever invoke them,
so instead emit symbols that just trap.
We should stop emitting references to these symbols, but still need to emit
definitions for compatibility.
llvm-svn: 296275
2017-02-26 07:53:05 +08:00
|
|
|
|
|
|
|
struct nothrow_t {} nothrow;
|
|
|
|
void *operator new(decltype(sizeof(0)), nothrow_t) noexcept;
|
|
|
|
|
|
|
|
namespace PotentiallyConstructed {
|
|
|
|
template<bool NE> struct A {
|
|
|
|
A() noexcept(NE);
|
|
|
|
A(const A&) noexcept(NE);
|
|
|
|
A(A&&) noexcept(NE);
|
|
|
|
A &operator=(const A&) noexcept(NE);
|
|
|
|
A &operator=(A&&) noexcept(NE);
|
|
|
|
~A() noexcept(NE);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<bool NE> struct B : virtual A<NE> {};
|
|
|
|
|
|
|
|
template<bool NE> struct C : virtual A<NE> {
|
|
|
|
virtual void f() = 0; // expected-note 2{{unimplemented}}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<bool NE> struct D final : C<NE> {
|
|
|
|
void f();
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, bool A, bool B, bool C, bool D, bool E, bool F> void check() {
|
|
|
|
T *p = nullptr;
|
|
|
|
T &a = *p;
|
|
|
|
static_assert(noexcept(a = a) == D, "");
|
|
|
|
static_assert(noexcept(a = static_cast<T&&>(a)) == E, "");
|
2017-08-31 04:25:22 +08:00
|
|
|
static_assert(noexcept(delete &a) == F, "");
|
C++ DR1611, 1658, 2180: implement "potentially constructed subobject" rules for special member functions.
Essentially, as a base class constructor does not construct virtual bases, such
a constructor for an abstract class does not need the corresponding base class
construction to be valid, and likewise for destructors.
This creates an awkward situation: clang will sometimes generate references to
the complete object and deleting destructors for an abstract class (it puts
them in the construction vtable for a derived class). But we can't generate a
"correct" version of these because we can't generate references to base class
constructors any more (if they're template specializations, say, we might not
have instantiated them and can't assume any other TU will emit a copy).
Fortunately, we don't need to, since no correct program can ever invoke them,
so instead emit symbols that just trap.
We should stop emitting references to these symbols, but still need to emit
definitions for compatibility.
llvm-svn: 296275
2017-02-26 07:53:05 +08:00
|
|
|
|
|
|
|
// These are last because the first failure here causes instantiation to bail out.
|
|
|
|
static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}}
|
|
|
|
static_assert(noexcept(new (nothrow) T(a)) == B, "");
|
|
|
|
static_assert(noexcept(new (nothrow) T(static_cast<T&&>(a))) == C, "");
|
|
|
|
}
|
|
|
|
|
|
|
|
template void check<A<false>, 0, 0, 0, 0, 0, 0>();
|
|
|
|
template void check<A<true >, 1, 1, 1, 1, 1, 1>();
|
|
|
|
template void check<B<false>, 0, 0, 0, 0, 0, 0>();
|
|
|
|
template void check<B<true >, 1, 1, 1, 1, 1, 1>();
|
|
|
|
template void check<C<false>, 1, 1, 1, 0, 0, 0>(); // expected-note {{instantiation}}
|
|
|
|
template void check<C<true >, 1, 1, 1, 1, 1, 1>(); // expected-note {{instantiation}}
|
|
|
|
template void check<D<false>, 0, 0, 0, 0, 0, 0>();
|
|
|
|
template void check<D<true >, 1, 1, 1, 1, 1, 1>();
|
|
|
|
|
|
|
|
// ... the above trick doesn't work for this case...
|
|
|
|
struct Cfalse : virtual A<false> {
|
|
|
|
virtual void f() = 0;
|
|
|
|
|
|
|
|
Cfalse() noexcept;
|
|
|
|
Cfalse(const Cfalse&) noexcept;
|
|
|
|
Cfalse(Cfalse&&) noexcept;
|
|
|
|
};
|
|
|
|
Cfalse::Cfalse() noexcept = default;
|
|
|
|
Cfalse::Cfalse(const Cfalse&) noexcept = default;
|
|
|
|
Cfalse::Cfalse(Cfalse&&) noexcept = default;
|
|
|
|
}
|