r360988 - Revert Refactor constant evaluation of typeid(T) to track a symbolic type_info object rather than tracking the originating expression.

Chris Bieneman via cfe-commits cfe-commits at lists.llvm.org
Thu May 16 22:46:03 PDT 2019


Author: cbieneman
Date: Thu May 16 22:46:03 2019
New Revision: 360988

URL: http://llvm.org/viewvc/llvm-project?rev=360988&view=rev
Log:
Revert Refactor constant evaluation of typeid(T) to track a symbolic type_info object rather than tracking the originating expression.

This reverts r360974 (git commit 7ee4307bd4450022c3c8777f43a40cc4f0ccc009)

Modified:
    cfe/trunk/include/clang/AST/APValue.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/APValue.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/CodeGen/CGExprConstant.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/drs/dr19xx.cpp
    cfe/trunk/test/Parser/MicrosoftExtensions.cpp
    cfe/trunk/test/SemaCXX/builtin-constant-p.cpp
    cfe/trunk/test/SemaCXX/typeid.cpp
    cfe/trunk/www/cxx_dr_status.html

Modified: cfe/trunk/include/clang/AST/APValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/APValue.h (original)
+++ cfe/trunk/include/clang/AST/APValue.h Thu May 16 22:46:03 2019
@@ -24,52 +24,14 @@ namespace clang {
   class AddrLabelExpr;
   class ASTContext;
   class CharUnits;
-  class CXXRecordDecl;
-  class Decl;
   class DiagnosticBuilder;
   class Expr;
   class FieldDecl;
-  struct PrintingPolicy;
-  class Type;
+  class Decl;
   class ValueDecl;
+  class CXXRecordDecl;
+  class QualType;
 
-/// Symbolic representation of typeid(T) for some type T.
-class TypeInfoLValue {
-  const Type *T;
-
-public:
-  TypeInfoLValue() : T() {}
-  explicit TypeInfoLValue(const Type *T);
-
-  const Type *getType() const { return T; }
-  explicit operator bool() const { return T; }
-
-  void *getOpaqueValue() { return const_cast<Type*>(T); }
-  static TypeInfoLValue getFromOpaqueValue(void *Value) {
-    TypeInfoLValue V;
-    V.T = reinterpret_cast<const Type*>(Value);
-    return V;
-  }
-
-  void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy) const;
-};
-}
-
-namespace llvm {
-template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> {
-  static void *getAsVoidPointer(clang::TypeInfoLValue V) {
-    return V.getOpaqueValue();
-  }
-  static clang::TypeInfoLValue getFromVoidPointer(void *P) {
-    return clang::TypeInfoLValue::getFromOpaqueValue(P);
-  }
-  // Validated by static_assert in APValue.cpp; hardcoded to avoid needing
-  // to include Type.h.
-  static constexpr int NumLowBitsAvailable = 3;
-};
-}
-
-namespace clang {
 /// APValue - This class implements a discriminated union of [uninitialized]
 /// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
 /// [Vector: N * APValue], [Array: N * APValue]
@@ -95,18 +57,13 @@ public:
 
   class LValueBase {
   public:
-    typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue>
-        PtrTy;
+    typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
 
-    LValueBase() : Local{} {}
+    LValueBase() : CallIndex(0), Version(0) {}
 
     template <class T>
-    LValueBase(T P, unsigned I = 0, unsigned V = 0) : Ptr(P), Local{I, V} {
-      assert(!is<TypeInfoLValue>() &&
-             "don't use this constructor to form a type_info lvalue");
-    }
-
-    static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
+    LValueBase(T P, unsigned I = 0, unsigned V = 0)
+        : Ptr(P), CallIndex(I), Version(V) {}
 
     template <class T>
     bool is() const { return Ptr.is<T>(); }
@@ -121,15 +78,28 @@ public:
 
     bool isNull() const;
 
-    explicit operator bool() const;
+    explicit operator bool () const;
 
-    PtrTy getPointer() const { return Ptr; }
+    PtrTy getPointer() const {
+      return Ptr;
+    }
 
-    unsigned getCallIndex() const;
-    unsigned getVersion() const;
-    QualType getTypeInfoType() const;
+    unsigned getCallIndex() const {
+      return CallIndex;
+    }
 
-    friend bool operator==(const LValueBase &LHS, const LValueBase &RHS);
+    void setCallIndex(unsigned Index) {
+      CallIndex = Index;
+    }
+
+    unsigned getVersion() const {
+      return Version;
+    }
+
+    friend bool operator==(const LValueBase &LHS, const LValueBase &RHS) {
+      return LHS.Ptr == RHS.Ptr && LHS.CallIndex == RHS.CallIndex &&
+             LHS.Version == RHS.Version;
+    }
     friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) {
       return !(LHS == RHS);
     }
@@ -137,14 +107,7 @@ public:
 
   private:
     PtrTy Ptr;
-    struct LocalState {
-      unsigned CallIndex, Version;
-    };
-    union {
-      LocalState Local;
-      /// The type std::type_info, if this is a TypeInfoLValue.
-      void *TypeInfoType;
-    };
+    unsigned CallIndex, Version;
   };
 
   /// A FieldDecl or CXXRecordDecl, along with a flag indicating whether we

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu May 16 22:46:03 2019
@@ -160,9 +160,6 @@ def note_constexpr_access_static_tempora
   "dynamic_cast of}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">;
 def note_constexpr_modify_global : Note<
   "a constant expression cannot modify an object that is visible outside "
   "that expression">;

Modified: cfe/trunk/lib/AST/APValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/lib/AST/APValue.cpp (original)
+++ cfe/trunk/lib/AST/APValue.cpp Thu May 16 22:46:03 2019
@@ -20,56 +20,6 @@
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
-/// The identity of a type_info object depends on the canonical unqualified
-/// type only.
-TypeInfoLValue::TypeInfoLValue(const Type *T)
-    : T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
-
-void TypeInfoLValue::print(llvm::raw_ostream &Out,
-                           const PrintingPolicy &Policy) const {
-  Out << "typeid(";
-  QualType(getType(), 0).print(Out, Policy);
-  Out << ")";
-}
-
-static_assert(
-    1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
-        alignof(const Type *),
-    "Type is insufficiently aligned");
-
-APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
-                                                     QualType TypeInfo) {
-  LValueBase Base;
-  Base.Ptr = LV;
-  Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
-  return Base;
-}
-
-unsigned APValue::LValueBase::getCallIndex() const {
-  return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
-}
-
-unsigned APValue::LValueBase::getVersion() const {
-  return is<TypeInfoLValue>() ? 0 : Local.Version;
-}
-
-QualType APValue::LValueBase::getTypeInfoType() const {
-  assert(is<TypeInfoLValue>() && "not a type_info lvalue");
-  return QualType::getFromOpaquePtr(TypeInfoType);
-}
-
-namespace clang {
-bool operator==(const APValue::LValueBase &LHS,
-                const APValue::LValueBase &RHS) {
-  if (LHS.Ptr != RHS.Ptr)
-    return false;
-  if (LHS.is<TypeInfoLValue>())
-    return true;
-  return LHS.Local.CallIndex == RHS.Local.CallIndex &&
-         LHS.Local.Version == RHS.Local.Version;
-}
-}
-
 namespace {
   struct LVBase {
     APValue::LValueBase Base;
@@ -110,8 +60,6 @@ llvm::DenseMapInfo<clang::APValue::LValu
 
 namespace clang {
 llvm::hash_code hash_value(const APValue::LValueBase &Base) {
-  if (Base.is<TypeInfoLValue>())
-    return llvm::hash_value(Base.getOpaqueValue());
   return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
                             Base.getVersion());
 }
@@ -522,9 +470,7 @@ void APValue::printPretty(raw_ostream &O
 
       if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
         Out << *VD;
-      else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
-        TI.print(Out, Ctx.getPrintingPolicy());
-      } else {
+      else {
         assert(Base.get<const Expr *>() != nullptr &&
                "Expecting non-null Expr");
         Base.get<const Expr*>()->printPretty(Out, nullptr,
@@ -549,9 +495,6 @@ void APValue::printPretty(raw_ostream &O
     if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
       Out << *VD;
       ElemTy = VD->getType();
-    } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
-      TI.print(Out, Ctx.getPrintingPolicy());
-      ElemTy = Base.getTypeInfoType();
     } else {
       const Expr *E = Base.get<const Expr*>();
       assert(E != nullptr && "Expecting non-null Expr");

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Thu May 16 22:46:03 2019
@@ -87,9 +87,6 @@ namespace {
       return D->getType();
     }
 
-    if (TypeInfoLValue TI = B.dyn_cast<TypeInfoLValue>())
-      return B.getTypeInfoType();
-
     const Expr *Base = B.get<const Expr*>();
 
     // For a materialized temporary, the type of the temporary we materialized
@@ -1786,9 +1783,6 @@ static bool IsGlobalLValue(APValue::LVal
     return isa<FunctionDecl>(D);
   }
 
-  if (B.is<TypeInfoLValue>())
-    return true;
-
   const Expr *E = B.get<const Expr*>();
   switch (E->getStmtClass()) {
   default:
@@ -1806,6 +1800,7 @@ static bool IsGlobalLValue(APValue::LVal
   case Expr::PredefinedExprClass:
   case Expr::ObjCStringLiteralClass:
   case Expr::ObjCEncodeExprClass:
+  case Expr::CXXTypeidExprClass:
   case Expr::CXXUuidofExprClass:
     return true;
   case Expr::ObjCBoxedExprClass:
@@ -1883,9 +1878,9 @@ static void NoteLValueLocation(EvalInfo
   const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
   if (VD)
     Info.Note(VD->getLocation(), diag::note_declared_at);
-  else if (const Expr *E = Base.dyn_cast<const Expr*>())
-    Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
-  // We have no information to show for a typeid(T) object.
+  else
+    Info.Note(Base.get<const Expr*>()->getExprLoc(),
+              diag::note_constexpr_temporary_here);
 }
 
 /// Check that this reference or pointer core constant expression is a valid
@@ -3409,7 +3404,7 @@ static CompleteObject findCompleteObject
 
     if (!Frame) {
       if (const MaterializeTemporaryExpr *MTE =
-              dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
+              dyn_cast<MaterializeTemporaryExpr>(Base)) {
         assert(MTE->getStorageDuration() == SD_Static &&
                "should have a frame for a non-global materialized temporary");
 
@@ -3444,13 +3439,7 @@ static CompleteObject findCompleteObject
       } else {
         if (!IsAccess)
           return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
-        APValue Val;
-        LVal.moveInto(Val);
-        Info.FFDiag(E, diag::note_constexpr_access_unreadable_object)
-            << AK
-            << Val.getAsString(Info.Ctx,
-                               Info.Ctx.getLValueReferenceType(LValType));
-        NoteLValueLocation(Info, LVal.Base);
+        Info.FFDiag(E);
         return CompleteObject();
       }
     } else {
@@ -5788,13 +5777,13 @@ public:
 // - Literals
 //  * CompoundLiteralExpr in C (and in global scope in C++)
 //  * StringLiteral
+//  * CXXTypeidExpr
 //  * PredefinedExpr
 //  * ObjCStringLiteralExpr
 //  * ObjCEncodeExpr
 //  * AddrLabelExpr
 //  * BlockExpr
 //  * CallExpr for a MakeStringConstant builtin
-// - typeid(T) expressions, as TypeInfoLValues
 // - Locals and temporaries
 //  * MaterializeTemporaryExpr
 //  * Any Expr, with a CallIndex indicating the function in which the temporary
@@ -6029,14 +6018,8 @@ LValueExprEvaluator::VisitCompoundLitera
 }
 
 bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
-  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()));
-  }
+  if (!E->isPotentiallyEvaluated())
+    return Success(E);
 
   Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
     << E->getExprOperand()->getType()
@@ -6632,11 +6615,9 @@ bool PointerExprEvaluator::VisitBuiltinC
       if (const ValueDecl *VD =
           OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
         BaseAlignment = Info.Ctx.getDeclAlign(VD);
-      } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) {
-        BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf);
       } else {
-        BaseAlignment = GetAlignOfType(
-            Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
+        BaseAlignment = GetAlignOfExpr(
+            Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf);
       }
 
       if (BaseAlignment < Align) {
@@ -8354,10 +8335,6 @@ static bool EvaluateBuiltinConstantPForL
     if (!isa<StringLiteral>(E))
       return false;
     return LV.getLValueOffset().isZero();
-  } else if (Base.is<TypeInfoLValue>()) {
-    // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to
-    // evaluate to true.
-    return true;
   } else {
     // Any other base is not constant enough for GCC.
     return false;
@@ -8422,8 +8399,6 @@ static QualType getObjectType(APValue::L
   } else if (const Expr *E = B.get<const Expr*>()) {
     if (isa<CompoundLiteralExpr>(E))
       return E->getType();
-  } else if (B.is<TypeInfoLValue>()) {
-    return B.getTypeInfoType();
   }
 
   return QualType();

Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu May 16 22:46:03 2019
@@ -1735,17 +1735,6 @@ ConstantLValueEmitter::tryEmitBase(const
     return nullptr;
   }
 
-  // Handle typeid(T).
-  if (TypeInfoLValue TI = base.dyn_cast<TypeInfoLValue>()) {
-    llvm::Type *StdTypeInfoPtrTy =
-        CGM.getTypes().ConvertType(base.getTypeInfoType())->getPointerTo();
-    llvm::Constant *TypeInfo =
-        CGM.GetAddrOfRTTIDescriptor(QualType(TI.getType(), 0));
-    if (TypeInfo->getType() != StdTypeInfoPtrTy)
-      TypeInfo = llvm::ConstantExpr::getBitCast(TypeInfo, StdTypeInfoPtrTy);
-    return TypeInfo;
-  }
-
   // Otherwise, it must be an expression.
   return Visit(base.get<const Expr*>());
 }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 16 22:46:03 2019
@@ -6424,11 +6424,8 @@ ExprResult Sema::CheckTemplateArgument(N
       // -- a string literal
       // -- the result of a typeid expression, or
       // -- a predefined __func__ variable
-      APValue::LValueBase Base = Value.getLValueBase();
-      auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
-      if (Base && !VD) {
-        auto *E = Base.dyn_cast<const Expr *>();
-        if (E && isa<CXXUuidofExpr>(E)) {
+      if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
+        if (isa<CXXUuidofExpr>(E)) {
           Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
           break;
         }
@@ -6436,6 +6433,8 @@ ExprResult Sema::CheckTemplateArgument(N
             << Arg->getSourceRange();
         return ExprError();
       }
+      auto *VD = const_cast<ValueDecl *>(
+          Value.getLValueBase().dyn_cast<const ValueDecl *>());
       // -- a subobject
       if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
           VD && VD->getType()->isArrayType() &&

Modified: cfe/trunk/test/CXX/drs/dr19xx.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr19xx.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/test/CXX/drs/dr19xx.cpp (original)
+++ cfe/trunk/test/CXX/drs/dr19xx.cpp Thu May 16 22:46:03 2019
@@ -167,14 +167,9 @@ namespace dr1959 { // dr1959: 3.9
 #endif
 }
 
-namespace dr1968 { // dr1968: no
+namespace dr1968 { // dr1968: yes
 #if __cplusplus >= 201103L
-  // FIXME: According to DR1968, both of these should be considered
-  // non-constant.
-  static_assert(&typeid(int) == &typeid(int), "");
-
-  constexpr const std::type_info *f() { return &typeid(int); }
-  static_assert(f() == f(), "");
+  static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an integral constant expression}}
 #endif
 }
 

Modified: cfe/trunk/test/Parser/MicrosoftExtensions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/MicrosoftExtensions.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/test/Parser/MicrosoftExtensions.cpp (original)
+++ cfe/trunk/test/Parser/MicrosoftExtensions.cpp Thu May 16 22:46:03 2019
@@ -138,8 +138,6 @@ typedef COM_CLASS_TEMPLATE_REF<struct_wi
 COM_CLASS_TEMPLATE_REF<int, __uuidof(struct_with_uuid)> good_template_arg;
 
 COM_CLASS_TEMPLATE<int, __uuidof(struct_with_uuid)> bad_template_arg; // expected-error {{non-type template argument of type 'const _GUID' is not a constant expression}}
-// expected-note at -1 {{read of object '__uuidof(struct_with_uuid)' whose value is not known}}
-// expected-note at -2 {{temporary created here}}
 
 namespace PR16911 {
 struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;

Modified: cfe/trunk/test/SemaCXX/builtin-constant-p.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-constant-p.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/builtin-constant-p.cpp (original)
+++ cfe/trunk/test/SemaCXX/builtin-constant-p.cpp Thu May 16 22:46:03 2019
@@ -130,8 +130,3 @@ constexpr int mutate6(bool mutate) {
 static_assert(mutate6(false) == 11);
 // Mutation of state outside __builtin_constant_p: evaluates to false.
 static_assert(mutate6(true) == 10);
-
-// GCC strangely returns true for the address of a type_info object, despite it
-// not being a pointer to the start of a string literal.
-namespace std { struct type_info; }
-static_assert(__builtin_constant_p(&typeid(int)));

Modified: cfe/trunk/test/SemaCXX/typeid.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/typeid.cpp?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/typeid.cpp (original)
+++ cfe/trunk/test/SemaCXX/typeid.cpp Thu May 16 22:46:03 2019
@@ -6,7 +6,7 @@ void f()
 }
 
 namespace std {
-  struct type_info { const char *name; };
+  class type_info;
 }
 
 void g()
@@ -27,6 +27,3 @@ void h(int i) {
   typeid(V);        // expected-error{{'typeid' of variably modified type 'char [i]'}}
   typeid(char [i]); // expected-error{{'typeid' of variably modified type 'char [i]'}}
 }
-
-// expected-note at +1 {{read of object 'typeid(int).name' whose value is not known}}
-constexpr const char *name = typeid(int).name; // expected-error {{constant expression}}

Modified: cfe/trunk/www/cxx_dr_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_dr_status.html?rev=360988&r1=360987&r2=360988&view=diff
==============================================================================
--- cfe/trunk/www/cxx_dr_status.html (original)
+++ cfe/trunk/www/cxx_dr_status.html Thu May 16 22:46:03 2019
@@ -11623,7 +11623,7 @@ and <I>POD class</I></td>
     <td><a href="http://wg21.link/cwg1968">1968</a></td>
     <td>NAD</td>
     <td>Address of <TT>typeid</TT> in constant expressions</td>
-    <td class="none" align="center">No</td>
+    <td class="full" align="center">Yes</td>
   </tr>
   <tr class="open" id="1969">
     <td><a href="http://wg21.link/cwg1969">1969</a></td>




More information about the cfe-commits mailing list