r361067 - [c++20] P1327R1: Support for typeid applied to objects of polymorphic

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri May 17 12:19:28 PDT 2019


Author: rsmith
Date: Fri May 17 12:19:28 2019
New Revision: 361067

URL: http://llvm.org/viewvc/llvm-project?rev=361067&view=rev
Log:
[c++20] P1327R1: Support for typeid applied to objects of polymorphic
class type in constant evaluation.

This reinstates r360977, reverted in r360987, now that its rerequisite
patch is reinstated and fixed.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
    cfe/trunk/www/cxx_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=361067&r1=361066&r2=361067&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Fri May 17 12:19:28 2019
@@ -12,7 +12,8 @@ let Component = "AST" in {
 def note_expr_divide_by_zero : Note<"division by zero">;
 def note_constexpr_invalid_cast : Note<
   "%select{reinterpret_cast|dynamic_cast|cast that performs the conversions of"
-  " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+  " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression"
+  "%select{| in C++ standards before C++2a||}0">;
 def note_constexpr_invalid_downcast : Note<
   "cannot cast object of dynamic type %0 to type %1">;
 def note_constexpr_overflow : Note<
@@ -31,12 +32,13 @@ 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 call to virtual function in a constant expression">;
+  "cannot evaluate call to virtual function in a constant expression "
+  "in C++ standards before C++2a">;
 def note_constexpr_pure_virtual_call : Note<
   "pure virtual function %q0 called">;
 def note_constexpr_polymorphic_unknown_dynamic_type : Note<
-  "%select{||||virtual function called on|dynamic_cast applied to}0 "
-  "object '%1' whose dynamic type is not constant">;
+  "%select{||||virtual function called on|dynamic_cast applied to|"
+  "typeid applied to}0 object '%1' whose dynamic type is not constant">;
 def note_constexpr_dynamic_cast_to_reference_failed : Note<
   "reference dynamic_cast failed: %select{"
   "static type %1 of operand is a non-public base class of dynamic type %2|"
@@ -90,7 +92,7 @@ def note_constexpr_var_init_non_constant
   "initializer of %0 is not a constant expression">;
 def note_constexpr_typeid_polymorphic : Note<
   "typeid applied to expression of polymorphic type %0 is "
-  "not allowed in a constant expression">;
+  "not allowed in a constant expression in C++ standards before C++2a">;
 def note_constexpr_void_comparison : Note<
   "comparison between unequal pointers to void has unspecified result">;
 def note_constexpr_temporary_here : Note<"temporary created here">;
@@ -108,11 +110,11 @@ def note_constexpr_this : Note<
   "evaluation of a call to a 'constexpr' member function">;
 def note_constexpr_lifetime_ended : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "%select{temporary|variable}1 whose lifetime has ended">;
 def note_constexpr_access_uninit : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "object outside its lifetime is not allowed in a constant expression">;
 def note_constexpr_use_uninit_reference : Note<
   "use of reference outside its lifetime "
@@ -139,30 +141,30 @@ def note_constexpr_ltor_incomplete_type
   "read of incomplete type %0 is not allowed in a constant expression">;
 def note_constexpr_access_null : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "dereferenced null pointer is not allowed in a constant expression">;
 def note_constexpr_access_past_end : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "dereferenced one-past-the-end pointer is not allowed in a constant expression">;
 def note_constexpr_access_unsized_array : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "element of array without known bound "
   "is not allowed in a constant expression">;
 def note_constexpr_access_inactive_union_member : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 "
+  "dynamic_cast of|typeid applied to}0 "
   "member %1 of union with %select{active member %3|no active member}2 "
   "is not allowed in a constant expression">;
 def note_constexpr_access_static_temporary : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 temporary "
+  "dynamic_cast of|typeid applied to}0 temporary "
   "is not allowed in a constant expression outside the expression that "
   "created the temporary">;
 def note_constexpr_access_unreadable_object : Note<
   "%select{read of|assignment to|increment of|decrement of|member call on|"
-  "dynamic_cast of}0 object '%1' whose value is not known">;
+  "dynamic_cast of|typeid applied to}0 object '%1' whose value is not known">;
 def note_constexpr_modify_global : Note<
   "a constant expression cannot modify an object that is visible outside "
   "that expression">;

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=361067&r1=361066&r2=361067&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri May 17 12:19:28 2019
@@ -1349,6 +1349,7 @@ enum AccessKinds {
   AK_Decrement,
   AK_MemberCall,
   AK_DynamicCast,
+  AK_TypeId,
 };
 
 static bool isModification(AccessKinds AK) {
@@ -1356,6 +1357,7 @@ static bool isModification(AccessKinds A
   case AK_Read:
   case AK_MemberCall:
   case AK_DynamicCast:
+  case AK_TypeId:
     return false;
   case AK_Assign:
   case AK_Increment:
@@ -6034,19 +6036,33 @@ LValueExprEvaluator::VisitCompoundLitera
 }
 
 bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
+  TypeInfoLValue TypeInfo;
+
   if (!E->isPotentiallyEvaluated()) {
-    TypeInfoLValue TypeInfo;
     if (E->isTypeOperand())
       TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr());
     else
       TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr());
-    return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
+  } else {
+    if (!Info.Ctx.getLangOpts().CPlusPlus2a) {
+      Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
+        << E->getExprOperand()->getType()
+        << E->getExprOperand()->getSourceRange();
+    }
+
+    if (!Visit(E->getExprOperand()))
+      return false;
+
+    Optional<DynamicType> DynType =
+        ComputeDynamicType(Info, E, Result, AK_TypeId);
+    if (!DynType)
+      return false;
+
+    TypeInfo =
+        TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr());
   }
 
-  Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
-    << E->getExprOperand()->getType()
-    << E->getExprOperand()->getSourceRange();
-  return false;
+  return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
 }
 
 bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp?rev=361067&r1=361066&r2=361067&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp Fri May 17 12:19:28 2019
@@ -2,6 +2,10 @@
 
 #include "Inputs/std-compare.h"
 
+namespace std {
+  struct type_info;
+};
+
 namespace ThreeWayComparison {
   struct A {
     int n;
@@ -354,3 +358,58 @@ namespace DynamicCast {
   // expected-note at +1 {{reference dynamic_cast failed: dynamic type 'DynamicCast::G' of operand does not have a base class of type 'DynamicCast::Unrelated'}}
   constexpr int e_unrelated = (dynamic_cast<Unrelated&>((E&)g), 0); // expected-error {{}}
 }
+
+namespace TypeId {
+  struct A {
+    const std::type_info &ti = typeid(*this);
+  };
+  struct A2 : A {};
+  static_assert(&A().ti == &typeid(A));
+  static_assert(&typeid((A2())) == &typeid(A2));
+  extern A2 extern_a2;
+  static_assert(&typeid(extern_a2) == &typeid(A2));
+
+  constexpr A2 a2;
+  constexpr const A &a1 = a2;
+  static_assert(&typeid(a1) == &typeid(A));
+
+  struct B {
+    virtual void f();
+    const std::type_info &ti1 = typeid(*this);
+  };
+  struct B2 : B {
+    const std::type_info &ti2 = typeid(*this);
+  };
+  static_assert(&B2().ti1 == &typeid(B));
+  static_assert(&B2().ti2 == &typeid(B2));
+  extern B2 extern_b2;
+  // expected-note at +1 {{typeid applied to object 'extern_b2' whose dynamic type is not constant}}
+  static_assert(&typeid(extern_b2) == &typeid(B2)); // expected-error {{constant expression}}
+
+  constexpr B2 b2;
+  constexpr const B &b1 = b2;
+  static_assert(&typeid(b1) == &typeid(B2));
+
+  constexpr bool side_effects() {
+    // Not polymorphic nor a glvalue.
+    bool OK = true;
+    (void)typeid(OK = false, A2()); // expected-warning {{has no effect}}
+    if (!OK) return false;
+
+    // Not polymorphic.
+    A2 a2;
+    (void)typeid(OK = false, a2); // expected-warning {{has no effect}}
+    if (!OK) return false;
+
+    // Not a glvalue.
+    (void)typeid(OK = false, B2()); // expected-warning {{has no effect}}
+    if (!OK) return false;
+
+    // Polymorphic glvalue: operand evaluated.
+    OK = false;
+    B2 b2;
+    (void)typeid(OK = true, b2); // expected-warning {{will be evaluated}}
+    return OK;
+  }
+  static_assert(side_effects());
+}

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=361067&r1=361066&r2=361067&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Fri May 17 12:19:28 2019
@@ -973,10 +973,11 @@ as the draft C++2a standard evolves.
       </tr>
       <tr>
         <td><a href="http://wg21.link/p1327r1">P1327R1</a></td>
-        <td rowspan=2 class="none" align="center">No</td>
+        <td class="svn" align="center">SVN</td>
       </tr>
       <tr>
         <td><a href="http://wg21.link/p1330r0">P1330R0</a></td>
+        <td class="none" align="center">No</td>
       </tr>
     <tr>
       <td>Prohibit aggregates with user-declared constructors</td>




More information about the cfe-commits mailing list