r360370 - DR1872: don't allow any calls to virtual functions in constant

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu May 9 12:45:50 PDT 2019


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 at +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 at -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 at -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 at -3 {{copy assignment operator is implicitly deleted}}
+  // expected-error at -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>




More information about the cfe-commits mailing list