r284549 - DR1330: instantiate exception-specifications when "needed". We previously did
Alex L via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 23 08:01:53 PDT 2017
Hi Richard,
It looks like this commit caused PR34298 (https://bugs.llvm.org/show_bu
g.cgi?id=34298). Now Clang fails to compile a libc++ std::function member
variable with an incomplete return type. Libstdc++ works though, so I
assume that the right way to fix this is to change libc++?
Cheers,
Alex
On 19 October 2016 at 00:39, Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:
> Author: rsmith
> Date: Tue Oct 18 18:39:12 2016
> New Revision: 284549
>
> URL: http://llvm.org/viewvc/llvm-project?rev=284549&view=rev
> Log:
> DR1330: instantiate exception-specifications when "needed". We previously
> did
> not instantiate exception specifications of functions if they were only
> used in
> unevaluated contexts (other than 'noexcept' expressions).
>
> In C++17 onwards, this becomes essential since the exception specification
> is
> now part of the function's type.
>
> Note that this means that constructs like the following no longer work:
>
> struct A {
> static T f() noexcept(...);
> decltype(f()) *p;
> };
>
> ... because the decltype expression now needs the exception specification
> of
> 'f', which has not yet been parsed.
>
> Modified:
> cfe/trunk/lib/Sema/SemaExpr.cpp
> cfe/trunk/lib/Sema/SemaOverload.cpp
> cfe/trunk/test/CXX/drs/dr13xx.cpp
> cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
> cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
> cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
> cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> cfe/trunk/www/cxx_dr_status.html
>
> Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/
> SemaExpr.cpp?rev=284549&r1=284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 18 18:39:12 2016
> @@ -2889,6 +2889,14 @@ ExprResult Sema::BuildDeclarationNameExp
>
> {
> QualType type = VD->getType();
> + if (auto *FPT = type->getAs<FunctionProtoType>()) {
> + // C++ [except.spec]p17:
> + // An exception-specification is considered to be needed when:
> + // - in an expression, the function is the unique lookup result or
> + // the selected member of a set of overloaded functions.
> + ResolveExceptionSpec(Loc, FPT);
> + type = VD->getType();
> + }
> ExprValueKind valueKind = VK_RValue;
>
> switch (D->getKind()) {
> @@ -13138,6 +13146,19 @@ void Sema::MarkFunctionReferenced(Source
> Func->getMemberSpecializationInfo()))
> checkSpecializationVisibility(Loc, Func);
>
> + // C++14 [except.spec]p17:
> + // An exception-specification is considered to be needed when:
> + // - the function is odr-used or, if it appears in an unevaluated
> operand,
> + // would be odr-used if the expression were potentially-evaluated;
> + //
> + // Note, we do this even if MightBeOdrUse is false. That indicates that
> the
> + // function is a pure virtual function we're calling, and in that case
> the
> + // function was selected by overload resolution and we need to resolve
> its
> + // exception specification for a different reason.
> + const FunctionProtoType *FPT = Func->getType()->getAs<
> FunctionProtoType>();
> + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
> + ResolveExceptionSpec(Loc, FPT);
> +
> // If we don't need to mark the function as used, and we don't need to
> // try to provide a definition, there's nothing more to do.
> if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) &&
> @@ -13196,12 +13217,6 @@ void Sema::MarkFunctionReferenced(Source
> // FIXME: Is this really right?
> if (CurContext == Func) return;
>
> - // Resolve the exception specification for any function which is
> - // used: CodeGen will need it.
> - const FunctionProtoType *FPT = Func->getType()->getAs<
> FunctionProtoType>();
> - if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
> - ResolveExceptionSpec(Loc, FPT);
> -
> // Implicit instantiation of function templates and member functions of
> // class templates.
> if (Func->isImplicitlyInstantiable()) {
>
> Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/
> SemaOverload.cpp?rev=284549&r1=284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 18 18:39:12 2016
> @@ -13166,6 +13166,13 @@ Expr *Sema::FixOverloadedFunctionReferen
> UnOp->getOperatorLoc());
> }
>
> + // C++ [except.spec]p17:
> + // An exception-specification is considered to be needed when:
> + // - in an expression the function is the unique lookup result or the
> + // selected member of a set of overloaded functions
> + if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>())
> + ResolveExceptionSpec(E->getExprLoc(), FPT);
> +
> if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
> // FIXME: avoid copy.
> TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr;
>
> Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/
> drs/dr13xx.cpp?rev=284549&r1=284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/CXX/drs/dr13xx.cpp (original)
> +++ cfe/trunk/test/CXX/drs/dr13xx.cpp Tue Oct 18 18:39:12 2016
> @@ -3,6 +3,91 @@
> // RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions
> -pedantic-errors
> // RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions
> -pedantic-errors
>
> +namespace dr1330 { // dr1330: 4.0 c++11
> + // exception-specifications are parsed in a context where the class is
> complete.
> + struct A {
> + void f() throw(T) {}
> + struct T {};
> +
> +#if __cplusplus >= 201103L
> + void g() noexcept(&a == b) {}
> + static int a;
> + static constexpr int *b = &a;
> +#endif
> + };
> +
> + void (A::*af1)() throw(A::T) = &A::f;
> + void (A::*af2)() throw() = &A::f; // expected-error-re {{{{not
> superset|different exception spec}}}}
> +
> +#if __cplusplus >= 201103L
> + static_assert(noexcept(A().g()), "");
> +#endif
> +
> + // Likewise, they're instantiated separately from an enclosing class
> template.
> + template<typename U>
> + struct B {
> + void f() throw(T, typename U::type) {}
> + struct T {};
> +
> +#if __cplusplus >= 201103L
> + void g() noexcept(&a == b && U::value) {}
> + static int a;
> + static constexpr int *b = &a;
> +#endif
> + };
> +
> + B<int> bi; // ok
> +
> + struct P {
> + typedef int type;
> + static const int value = true;
> + };
> +
> + void (B<P>::*bpf1)() throw(B<P>::T, int) = &B<P>::f;
> +#if __cplusplus < 201103L
> + // expected-error at -2 {{not superset}}
> + // FIXME: We only delay instantiation in C++11 onwards. In C++98,
> something
> + // weird happens: instantiation of B<P> fails because it references T
> before
> + // it's instantiated, but the diagnostic is suppressed in
> + // Sema::FindInstantiatedDecl because we've already hit an error. This
> is
> + // obviously a bad way to react to this situation; we should still
> producing
> + // the "T has not yet been instantiated" error here, rather than giving
> + // confusing errors later on.
> +#endif
> + void (B<P>::*bpf2)() throw(int) = &B<P>::f; // expected-error-re
> {{{{not superset|different exception spec}}}}
> + void (B<P>::*bpf3)() = &B<P>::f;
> +
> +#if __cplusplus >= 201103L
> + static_assert(noexcept(B<P>().g()), "");
> + struct Q { static const int value = false; };
> + static_assert(!noexcept(B<Q>().g()), "");
> +#endif
> +
> + template<typename T> int f() throw(typename T::error) { return 0; } //
> expected-error 1-4{{prior to '::'}} expected-note 0-1{{instantiation of}}
> + // An exception-specification is needed even if the function is only
> used in
> + // an unevaluated operand.
> + int f1 = sizeof(f<int>()); // expected-note {{instantiation of}}
> +#if __cplusplus >= 201103L
> + decltype(f<char>()) f2; // expected-note {{instantiation of}}
> + bool f3 = noexcept(f<float>()); // expected-note {{instantiation of}}
> +#endif
> + template int f<short>(); // expected-note {{instantiation of}}
> +
> + template<typename T> struct C {
> + C() throw(typename T::type); // expected-error 1-2{{prior to '::'}}
> + };
> + struct D : C<void> {}; // ok
> +#if __cplusplus < 201103L
> + // expected-note at -2 {{instantiation of}}
> +#endif
> + void f(D &d) { d = d; } // ok
> +
> + // FIXME: In C++11 onwards, we should also note the declaration of 'e'
> as the
> + // line that triggers the use of E::E()'s exception specification.
> + struct E : C<int> {}; // expected-note {{in instantiation of}}
> + E e;
> +}
> +
> namespace dr1346 { // dr1346: 3.5
> auto a(1); // expected-error 0-1{{extension}}
> auto b(1, 2); // expected-error {{multiple expressions}} expected-error
> 0-1{{extension}}
>
> Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> SemaCXX/constant-expression-cxx1z.cpp?rev=284549&r1=
> 284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp (original)
> +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1z.cpp Tue Oct 18
> 18:39:12 2016
> @@ -25,3 +25,15 @@ namespace BaseClassAggregateInit {
> constexpr D d5 = { __INT_MAX__ }; // expected-error {{must be
> initialized by a constant expression}}
> // expected-note-re at -1 {{in call to 'A({{.*}})'}}
> }
> +
> +namespace NoexceptFunctionTypes {
> + template<typename T> constexpr bool f() noexcept(true) { return true; }
> + static_assert(f<int>());
> +
> + template<typename T> struct A {
> + constexpr bool f() noexcept(true) { return true; }
> + constexpr bool g() { return f(); }
> + };
> + static_assert(A<int>().f());
> + static_assert(A<int>().g());
> +}
>
> Modified: cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> SemaCXX/cxx0x-defaulted-functions.cpp?rev=284549&r1=
> 284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp (original)
> +++ cfe/trunk/test/SemaCXX/cxx0x-defaulted-functions.cpp Tue Oct 18
> 18:39:12 2016
> @@ -89,30 +89,34 @@ namespace DefaultedFnExceptionSpec {
> struct Error {
> void f() noexcept(T::error);
>
> - Error() noexcept(T::error); // expected-error {{type 'int' cannot be
> used prior to '::' because it has no members}}
> - Error(const Error&) noexcept(T::error);
> - Error(Error&&) noexcept(T::error);
> - Error &operator=(const Error&) noexcept(T::error);
> - Error &operator=(Error&&) noexcept(T::error);
> - ~Error() noexcept(T::error); // expected-error {{type 'int' cannot be
> used prior to '::' because it has no members}}
> + Error() noexcept(T::error); // expected-error {{type 'int' cannot be
> used prior to '::' because it has no members}} expected-error {{type
> 'char'}}
> + Error(const Error&) noexcept(T::error); // expected-error {{type
> 'int' cannot be used prior to '::' because it has no members}}
> + Error(Error&&) noexcept(T::error); // expected-error {{type 'int'
> cannot be used prior to '::' because it has no members}}
> + Error &operator=(const Error&) noexcept(T::error); // expected-error
> {{type 'int' cannot be used prior to '::' because it has no members}}
> expected-error {{type 'double'}}
> + Error &operator=(Error&&) noexcept(T::error); // expected-error
> {{type 'int' cannot be used prior to '::' because it has no members}}
> + ~Error() noexcept(T::error); // expected-error {{type 'int' cannot be
> used prior to '::' because it has no members}} expected-error {{type
> 'char'}}
> };
>
> + Error<char> c; // expected-note 2{{instantiation of}}
> struct DelayImplicit {
> - Error<int> e;
> + // FIXME: The location of this note is terrible. The instantiation was
> + // triggered by the uses of the functions in the decltype expressions
> below.
> + Error<int> e; // expected-note 6{{instantiation of}}
> };
> + Error<float> *e;
>
> - // Don't instantiate the exception specification here.
> + // An exception specification is needed if the exception specification
> for a
> + // a defaulted special member function that calls the function is
> needed.
> + // Use in an unevaluated operand still results in the exception spec
> being
> + // needed.
> void test1(decltype(declval<DelayImplicit>() =
> DelayImplicit(DelayImplicit())));
> void test2(decltype(declval<DelayImplicit>() = declval<const
> DelayImplicit>()));
> void test3(decltype(DelayImplicit(declval<const DelayImplicit>())));
>
> - // Any odr-use causes the exception specification to be evaluated.
> - struct OdrUse { // \
> - expected-note {{instantiation of exception specification for
> 'Error'}} \
> - expected-note {{instantiation of exception specification for
> '~Error'}}
> - Error<int> e;
> - };
> - OdrUse use; // expected-note {{implicit default constructor for
> 'DefaultedFnExceptionSpec::OdrUse' first required here}}
> + // Any odr-use needs the exception specification.
> + void f(Error<double> *p) {
> + *p = *p; // expected-note {{instantiation of}}
> + }
> }
>
> namespace PR13527 {
>
> Modified: cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> SemaCXX/libstdcxx_pair_swap_hack.cpp?rev=284549&r1=284548&
> r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp (original)
> +++ cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp Tue Oct 18
> 18:39:12 2016
> @@ -69,6 +69,7 @@ namespace sad {
>
> template<typename A, typename B> struct CLASS {
> void swap(CLASS &other) noexcept(noexcept(swap(*this, other))); //
> expected-error {{too many arguments}} expected-note {{declared here}}
> + // expected-error at -1{{uses itself}} expected-note at -1{{in
> instantiation of}}
> };
>
> CLASS<int, int> pi;
>
> Modified: cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/
> SemaTemplate/instantiate-exception-spec-cxx11.cpp?rev=
> 284549&r1=284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
> (original)
> +++ cfe/trunk/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp Tue
> Oct 18 18:39:12 2016
> @@ -30,8 +30,6 @@ template<unsigned N> struct S {
> // expected-error {{no member named 'recurse'}} \
> // expected-note 9{{instantiation of exception spec}}
> };
> -decltype(S<0>::recurse()) *pVoid1 = 0; // ok, exception spec not needed
> -decltype(&S<0>::recurse) pFn = 0; // ok, exception spec not needed
>
> template<> struct S<10> {};
> void (*pFn2)() noexcept = &S<0>::recurse; // expected-note
> {{instantiation of exception spec}} expected-error {{not superset}}
> @@ -39,7 +37,7 @@ void (*pFn2)() noexcept = &S<0>::recurse
>
> namespace dr1330_example {
> template <class T> struct A {
> - void f(...) throw (typename T::X); // expected-error {{'int'}}
> + void f(...) throw (typename T::X);
> void f(int);
> };
>
> @@ -48,16 +46,14 @@ namespace dr1330_example {
> }
>
> struct S {
> - template<typename T>
> - static int f() noexcept(noexcept(A<T>().f("boo!"))) { return 0; } //
> \
> - // expected-note {{instantiation of exception spec}}
> - typedef decltype(f<S>()) X;
> + template<typename T> static void f() throw(typename T::X);
> + typedef decltype(f<S>()) X; // expected-error {{exception
> specification is not available}}
> };
>
> - int test2() {
> - S().f<S>(); // ok
> - S().f<int>(); // expected-note {{instantiation of exception spec}}
> - }
> + struct T {
> + template<typename T> static void f() throw(T**);
> + typedef decltype(f<S>()) X; // expected-error {{exception
> specification is not available}}
> + };
>
> template<typename T>
> struct U {
>
> Modified: cfe/trunk/www/cxx_dr_status.html
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_
> status.html?rev=284549&r1=284548&r2=284549&view=diff
> ============================================================
> ==================
> --- cfe/trunk/www/cxx_dr_status.html (original)
> +++ cfe/trunk/www/cxx_dr_status.html Tue Oct 18 18:39:12 2016
> @@ -3613,7 +3613,7 @@ and <I>POD class</I></td>
> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
> closed.html#595">595</a></td>
> <td>dup</td>
> <td>Exception specifications in templates instantiated from class
> bodies</td>
> - <td class="none" align="center">Duplicate of <a
> href="#1330">1330</a></td>
> + <td class="svn" align="center">Duplicate of <a
> href="#1330">1330</a></td>
> </tr>
> <tr class="open" id="596">
> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
> active.html#596">596</a></td>
> @@ -7795,7 +7795,7 @@ and <I>POD class</I></td>
> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
> defects.html#1330">1330</a></td>
> <td>CD3</td>
> <td>Delayed instantiation of <TT>noexcept</TT> specifiers</td>
> - <td class="none" align="center">Unknown</td>
> + <td class="svn" align="center">SVN (C++11 onwards)</td>
> </tr>
> <tr class="open" id="1331">
> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_
> closed.html#1331">1331</a></td>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170823/bce6def9/attachment-0001.html>
More information about the cfe-commits
mailing list