sberg created this revision. sberg added reviewers: cfe-commits, rsmith. As discussed in [[ https://llvm.org/bugs/show_bug.cgi?id=24115 | "llvm-nm fails to build with gcc 5.1's libstdc++," ]] both llvm-nm and LibreOffice fail to build against GCC 5.1 libstdc++, due to Clang trying (and failing) to instantiate constexpr function templates referenced from within a decltype. See [[ https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/6udLpHDvShU | "Implicit instantiation of constexpr function template specialization called in decltype expression?" ]] for a stripped-down test case and a discussion why the Clang behaviour is considered wrong. There is a comment in test/SemaTemplate/constexpr-instantiate.cpp claiming this behaviour is in line with g++, but I cannot reproduce that neither with some GCC 5.1.1 nor with a recent GCC trunk build. The comment also says "FIXME: None of this is required by the C++ standard. The rules in this area are poorly specified, so this is subject to change.", and from the above build breakage I think it would be best to change the behaviour to not instantiate constexpr function templates merely because they are referenced from within a decltype. (Doing so of course breaks the test corresponding to that comment, so turn that test around to check the changed behaviour now.)
http://reviews.llvm.org/D13386 Files: lib/Sema/SemaExpr.cpp test/SemaTemplate/constexpr-instantiate.cpp Index: test/SemaTemplate/constexpr-instantiate.cpp =================================================================== --- test/SemaTemplate/constexpr-instantiate.cpp +++ test/SemaTemplate/constexpr-instantiate.cpp @@ -77,37 +77,23 @@ } namespace Unevaluated { - // We follow g++ in treating any reference to a constexpr function template - // specialization as requiring an instantiation, even if it occurs in an - // unevaluated context. - // - // We go slightly further than g++, and also trigger the implicit definition - // of a defaulted special member in the same circumstances. This seems scary, - // since a lot of classes have constexpr special members in C++11, but the - // only observable impact should be the implicit instantiation of constexpr - // special member templates (defaulted special members should only be - // generated if they are well-formed, and non-constexpr special members in a - // base or member cause the class's special member to not be constexpr). - // - // FIXME: None of this is required by the C++ standard. The rules in this - // area are poorly specified, so this is subject to change. namespace NotConstexpr { template<typename T> struct S { S() : n(0) {} S(const S&) : n(T::error) {} int n; }; struct U : S<int> {}; - decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it wasn't declared constexpr + decltype(U(U())) u; // ok, don't instantiate S<int>::S() } namespace Constexpr { template<typename T> struct S { constexpr S() : n(0) {} - constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}} + constexpr S(const S&) : n(T::error) {} int n; }; - struct U : S<int> {}; // expected-note {{instantiation}} - decltype(U(U())) u; // expected-note {{here}} + struct U : S<int> {}; + decltype(U(U())) u; // ok, don't instantiate S<int>::S() } namespace PR11851_Comment0 { Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12414,7 +12414,8 @@ // However, they cannot be referenced if they are deleted, and they are // deleted whenever the implicit definition of the special member would // fail. - if (!Func->isConstexpr() || Func->getBody()) + if (!Func->isConstexpr() || Func->getBody() || + ExprEvalContexts.back().IsDecltype) return; CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided()))
Index: test/SemaTemplate/constexpr-instantiate.cpp =================================================================== --- test/SemaTemplate/constexpr-instantiate.cpp +++ test/SemaTemplate/constexpr-instantiate.cpp @@ -77,37 +77,23 @@ } namespace Unevaluated { - // We follow g++ in treating any reference to a constexpr function template - // specialization as requiring an instantiation, even if it occurs in an - // unevaluated context. - // - // We go slightly further than g++, and also trigger the implicit definition - // of a defaulted special member in the same circumstances. This seems scary, - // since a lot of classes have constexpr special members in C++11, but the - // only observable impact should be the implicit instantiation of constexpr - // special member templates (defaulted special members should only be - // generated if they are well-formed, and non-constexpr special members in a - // base or member cause the class's special member to not be constexpr). - // - // FIXME: None of this is required by the C++ standard. The rules in this - // area are poorly specified, so this is subject to change. namespace NotConstexpr { template<typename T> struct S { S() : n(0) {} S(const S&) : n(T::error) {} int n; }; struct U : S<int> {}; - decltype(U(U())) u; // ok, don't instantiate S<int>::S() because it wasn't declared constexpr + decltype(U(U())) u; // ok, don't instantiate S<int>::S() } namespace Constexpr { template<typename T> struct S { constexpr S() : n(0) {} - constexpr S(const S&) : n(T::error) {} // expected-error {{has no members}} + constexpr S(const S&) : n(T::error) {} int n; }; - struct U : S<int> {}; // expected-note {{instantiation}} - decltype(U(U())) u; // expected-note {{here}} + struct U : S<int> {}; + decltype(U(U())) u; // ok, don't instantiate S<int>::S() } namespace PR11851_Comment0 { Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12414,7 +12414,8 @@ // However, they cannot be referenced if they are deleted, and they are // deleted whenever the implicit definition of the special member would // fail. - if (!Func->isConstexpr() || Func->getBody()) + if (!Func->isConstexpr() || Func->getBody() || + ExprEvalContexts.back().IsDecltype) return; CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided()))
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits