Author: rsmith Date: Thu May 9 12:45:49 2019 New Revision: 360370 URL: http://llvm.org/viewvc/llvm-project?rev=360370&view=rev Log: DR1872: don't allow any calls to virtual functions in constant evaluation.
Not even in cases where we would not actually perform virtual dispatch. Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp cfe/trunk/test/CXX/drs/dr13xx.cpp cfe/trunk/test/CXX/drs/dr18xx.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp cfe/trunk/www/cxx_dr_status.html Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu May 9 12:45:49 2019 @@ -31,7 +31,7 @@ def note_constexpr_invalid_inhctor : Not def note_constexpr_no_return : Note< "control reached end of constexpr function">; def note_constexpr_virtual_call : Note< - "cannot evaluate virtual function call in a constant expression">; + "cannot evaluate call to virtual function in a constant expression">; def note_constexpr_virtual_base : Note< "cannot construct object of type %0 with virtual base class " "in a constant expression">; Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu May 9 12:45:49 2019 @@ -4381,6 +4381,14 @@ static bool CheckConstexprFunction(EvalI return false; } + // DR1872: An instantiated virtual constexpr function can't be called in a + // constant expression. + if (isa<CXXMethodDecl>(Declaration) && + cast<CXXMethodDecl>(Declaration)->isVirtual()) { + Info.FFDiag(CallLoc, diag::note_constexpr_virtual_call); + return false; + } + // Can we evaluate this function call? if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl() && Body) @@ -4999,12 +5007,6 @@ public: if (This && !This->checkSubobject(Info, E, CSK_This)) return false; - // DR1358 allows virtual constexpr functions in some cases. Don't allow - // calls to such functions in constant expressions. - if (This && !HasQualifier && - isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isVirtual()) - return Error(E, diag::note_constexpr_virtual_call); - const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp (original) +++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp Thu May 9 12:45:49 2019 @@ -27,9 +27,9 @@ template<typename T> struct ImplicitVirt constexpr int ImplicitlyVirtual() const { return 0; } }; -constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}} +constexpr int a = ImplicitVirtualFromDependentBase<S>().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate call to virtual function}} constexpr int b = ImplicitVirtualFromDependentBase<T>().ImplicitlyVirtual(); // ok -constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual(); +constexpr int c = ImplicitVirtualFromDependentBase<S>().ImplicitVirtualFromDependentBase<S>::ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate call to virtual function}} template<typename R> struct ConstexprMember { constexpr R F() const { return 0; } Modified: cfe/trunk/test/CXX/drs/dr13xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr13xx.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr13xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr13xx.cpp Thu May 9 12:45:49 2019 @@ -267,6 +267,42 @@ namespace dr1347 { // dr1347: yes #endif } +namespace dr1358 { // dr1358: yes +#if __cplusplus >= 201103L + struct Lit { constexpr operator int() const { return 0; } }; + struct NonLit { NonLit(); operator int(); }; // expected-note 2{{no constexpr constructors}} + struct NonConstexprConv { constexpr operator int() const; }; + struct Virt { virtual int f(int) const; }; + + template<typename T, typename U, typename V> struct A : V { + int member; + constexpr A(U u) : member(u) {} + constexpr T f(U u) const { return T(); } + }; + + constexpr A<Lit, Lit, Lit> ce = Lit(); + constexpr int k = ce.f(Lit{}); + + // Can have a non-literal return type and parameter type. + // Constexpr function can be implicitly virtual. + A<NonLit, NonLit, Virt> a = NonLit(); + void g() { a.f(NonLit()); } + + // Constructor is still constexpr, so this is a literal type. + static_assert(__is_literal_type(decltype(a)), ""); + + // Constructor can call non-constexpr functions. + A<Lit, NonConstexprConv, Lit> b = NonConstexprConv(); + + // But the corresponding non-template cases are rejected. + struct B : Virt { + int member; + constexpr B(NonLit u) : member(u) {} // expected-error {{not a literal type}} + constexpr NonLit f(NonLit u) const { return NonLit(); } // expected-error {{not a literal type}} + }; +#endif +} + namespace dr1359 { // dr1359: 3.5 #if __cplusplus >= 201103L union A { constexpr A() = default; }; Modified: cfe/trunk/test/CXX/drs/dr18xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr18xx.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr18xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr18xx.cpp Thu May 9 12:45:49 2019 @@ -1,7 +1,8 @@ // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -// RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +// RUN: %clang_cc1 -std=c++2a -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors #if __cplusplus < 201103L // expected-error@+1 {{variadic macro}} @@ -41,6 +42,23 @@ namespace dr1815 { // dr1815: no #endif } +namespace dr1872 { // dr1872: 9 +#if __cplusplus >= 201103L + template<typename T> struct A : T { + constexpr int f() const { return 0; } + }; + struct X {}; + struct Y { virtual int f() const; }; + struct Z : virtual X {}; + + constexpr int x = A<X>().f(); + constexpr int y = A<Y>().f(); // expected-error {{constant expression}} expected-note {{call to virtual function}} + // Note, this is invalid even though it would not use virtual dispatch. + constexpr int y2 = A<Y>().A<Y>::f(); // expected-error {{constant expression}} expected-note {{call to virtual function}} + constexpr int z = A<Z>().f(); // expected-error {{constant expression}} expected-note {{non-literal type}} +#endif +} + namespace dr1881 { // dr1881: 7 struct A { int a : 4; }; struct B : A { int b : 3; }; @@ -56,19 +74,31 @@ namespace dr1881 { // dr1881: 7 void dr1891() { // dr1891: 4 #if __cplusplus >= 201103L int n; - auto a = []{}; // expected-note 2{{candidate}} expected-note 2{{here}} - auto b = [=]{ return n; }; // expected-note 2{{candidate}} expected-note 2{{here}} + auto a = []{}; // expected-note 0-4{{}} + auto b = [=]{ return n; }; // expected-note 0-4{{}} typedef decltype(a) A; typedef decltype(b) B; static_assert(!__has_trivial_constructor(A), ""); +#if __cplusplus > 201703L + // expected-error@-2 {{failed}} +#endif static_assert(!__has_trivial_constructor(B), ""); - A x; // expected-error {{no matching constructor}} + // C++20 allows default construction for non-capturing lambdas (P0624R2). + A x; +#if __cplusplus <= 201703L + // expected-error@-2 {{no matching constructor}} +#endif B y; // expected-error {{no matching constructor}} - a = a; // expected-error {{copy assignment operator is implicitly deleted}} - a = static_cast<A&&>(a); // expected-error {{copy assignment operator is implicitly deleted}} + // C++20 allows assignment for non-capturing lambdas (P0624R2). + a = a; + a = static_cast<A&&>(a); +#if __cplusplus <= 201703L + // expected-error@-3 {{copy assignment operator is implicitly deleted}} + // expected-error@-3 {{copy assignment operator is implicitly deleted}} +#endif b = b; // expected-error {{copy assignment operator is implicitly deleted}} b = static_cast<B&&>(b); // expected-error {{copy assignment operator is implicitly deleted}} #endif Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Thu May 9 12:45:49 2019 @@ -1862,7 +1862,7 @@ namespace VirtualFromBase { // Virtual f(), not OK. constexpr X<X<S1>> xxs1; constexpr X<S1> *p = const_cast<X<X<S1>>*>(&xxs1); - static_assert(p->f() == sizeof(X<S1>), ""); // expected-error {{constant expression}} expected-note {{virtual function call}} + static_assert(p->f() == sizeof(X<S1>), ""); // expected-error {{constant expression}} expected-note {{virtual function}} // Non-virtual f(), OK. constexpr X<X<S2>> xxs2; Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (original) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Thu May 9 12:45:49 2019 @@ -841,7 +841,7 @@ namespace VirtualFromBase { // Virtual f(), not OK. constexpr X<X<S2>> xxs2; constexpr X<S2> *q = const_cast<X<X<S2>>*>(&xxs2); - static_assert(q->f() == sizeof(X<S2>), ""); // expected-error {{constant expression}} expected-note {{virtual function call}} + static_assert(q->f() == sizeof(X<S2>), ""); // expected-error {{constant expression}} expected-note {{virtual function}} } namespace Lifetime { Modified: cfe/trunk/www/cxx_dr_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=360370&r1=360369&r2=360370&view=diff ============================================================================== --- cfe/trunk/www/cxx_dr_status.html (original) +++ cfe/trunk/www/cxx_dr_status.html Thu May 9 12:45:49 2019 @@ -7963,7 +7963,7 @@ and <I>POD class</I></td> <td><a href="http://wg21.link/cwg1358">1358</a></td> <td>CD3</td> <td>Unintentionally ill-formed <TT>constexpr</TT> function template instances</td> - <td class="none" align="center">Unknown</td> + <td class="full" align="center">Yes</td> </tr> <tr id="1359"> <td><a href="http://wg21.link/cwg1359">1359</a></td> @@ -11047,7 +11047,7 @@ and <I>POD class</I></td> <td><a href="http://wg21.link/cwg1872">1872</a></td> <td>CD4</td> <td>Instantiations of <TT>constexpr</TT> templates that cannot appear in constant expressions</td> - <td class="none" align="center">Unknown</td> + <td class="svn" align="center">SVN</td> </tr> <tr id="1873"> <td><a href="http://wg21.link/cwg1873">1873</a></td> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits