From 0446a431cf5657f55e363f18cc79198f10f7684c Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 9 May 2019 19:45:49 +0000 Subject: [PATCH] DR1872: don't allow any calls to virtual functions in constant evaluation. Not even in cases where we would not actually perform virtual dispatch. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@360370 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticASTKinds.td | 2 +- lib/AST/ExprConstant.cpp | 14 ++++--- .../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp | 4 +- test/CXX/drs/dr13xx.cpp | 36 ++++++++++++++++ test/CXX/drs/dr18xx.cpp | 42 ++++++++++++++++--- test/SemaCXX/constant-expression-cxx11.cpp | 2 +- test/SemaCXX/constant-expression-cxx1y.cpp | 2 +- www/cxx_dr_status.html | 4 +- 8 files changed, 87 insertions(+), 19 deletions(-) diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index b88b3626ed..821dc7ccad 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -31,7 +31,7 @@ def note_constexpr_invalid_inhctor : Note< 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">; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 11e753c077..3581d97c8b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4381,6 +4381,14 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; } + // DR1872: An instantiated virtual constexpr function can't be called in a + // constant expression. + if (isa(Declaration) && + cast(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(FD) && cast(FD)->isVirtual()) - return Error(E, diag::note_constexpr_virtual_call); - const FunctionDecl *Definition = nullptr; Stmt *Body = FD->getBody(Definition); diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp index 88ad6a4a3c..3b8274e273 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p6.cpp @@ -27,9 +27,9 @@ template struct ImplicitVirtualFromDependentBase : T { constexpr int ImplicitlyVirtual() const { return 0; } }; -constexpr int a = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate virtual function call}} +constexpr int a = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate call to virtual function}} constexpr int b = ImplicitVirtualFromDependentBase().ImplicitlyVirtual(); // ok -constexpr int c = ImplicitVirtualFromDependentBase().ImplicitVirtualFromDependentBase::ImplicitlyVirtual(); +constexpr int c = ImplicitVirtualFromDependentBase().ImplicitVirtualFromDependentBase::ImplicitlyVirtual(); // expected-error {{constant expression}} expected-note {{cannot evaluate call to virtual function}} template struct ConstexprMember { constexpr R F() const { return 0; } diff --git a/test/CXX/drs/dr13xx.cpp b/test/CXX/drs/dr13xx.cpp index 1d61e8687e..3a0b7d7ed4 100644 --- a/test/CXX/drs/dr13xx.cpp +++ b/test/CXX/drs/dr13xx.cpp @@ -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 struct A : V { + int member; + constexpr A(U u) : member(u) {} + constexpr T f(U u) const { return T(); } + }; + + constexpr A 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 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 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; }; diff --git a/test/CXX/drs/dr18xx.cpp b/test/CXX/drs/dr18xx.cpp index 16f967b656..5df132c368 100644 --- a/test/CXX/drs/dr18xx.cpp +++ b/test/CXX/drs/dr18xx.cpp @@ -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 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().f(); + constexpr int y = A().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().A::f(); // expected-error {{constant expression}} expected-note {{call to virtual function}} + constexpr int z = A().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); // expected-error {{copy assignment operator is implicitly deleted}} + // C++20 allows assignment for non-capturing lambdas (P0624R2). + a = a; + a = static_cast(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); // expected-error {{copy assignment operator is implicitly deleted}} #endif diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index 03491f4a87..6af43854b5 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1862,7 +1862,7 @@ namespace VirtualFromBase { // Virtual f(), not OK. constexpr X> xxs1; constexpr X *p = const_cast>*>(&xxs1); - static_assert(p->f() == sizeof(X), ""); // expected-error {{constant expression}} expected-note {{virtual function call}} + static_assert(p->f() == sizeof(X), ""); // expected-error {{constant expression}} expected-note {{virtual function}} // Non-virtual f(), OK. constexpr X> xxs2; diff --git a/test/SemaCXX/constant-expression-cxx1y.cpp b/test/SemaCXX/constant-expression-cxx1y.cpp index ed51cca82e..07ef7974d1 100644 --- a/test/SemaCXX/constant-expression-cxx1y.cpp +++ b/test/SemaCXX/constant-expression-cxx1y.cpp @@ -841,7 +841,7 @@ namespace VirtualFromBase { // Virtual f(), not OK. constexpr X> xxs2; constexpr X *q = const_cast>*>(&xxs2); - static_assert(q->f() == sizeof(X), ""); // expected-error {{constant expression}} expected-note {{virtual function call}} + static_assert(q->f() == sizeof(X), ""); // expected-error {{constant expression}} expected-note {{virtual function}} } namespace Lifetime { diff --git a/www/cxx_dr_status.html b/www/cxx_dr_status.html index d588961f56..6592e834eb 100755 --- a/www/cxx_dr_status.html +++ b/www/cxx_dr_status.html @@ -7963,7 +7963,7 @@ and POD class 1358 CD3 Unintentionally ill-formed constexpr function template instances - Unknown + Yes 1359 @@ -11047,7 +11047,7 @@ and POD class 1872 CD4 Instantiations of constexpr templates that cannot appear in constant expressions - Unknown + SVN 1873 -- 2.40.0