r360974 - Refactor constant evaluation of typeid(T) to track a symbolic type_info
Chris Bieneman via cfe-commits
cfe-commits at lists.llvm.org
Thu May 16 21:58:24 PDT 2019
Hey Richard,
This change is tripping up a bunch of the bots:
http://lab.llvm.org:8011/builders/clang-cmake-armv8-lld/builds/1397
I'm going to revert it so that we don't leave the bots broken overnight.
-Chris
> On May 16, 2019, at 6:46 PM, Richard Smith via cfe-commits <cfe-commits at lists.llvm.org> wrote:
>
> Author: rsmith
> Date: Thu May 16 18:46:05 2019
> New Revision: 360974
>
> URL: http://llvm.org/viewvc/llvm-project?rev=360974&view=rev
> Log:
> Refactor constant evaluation of typeid(T) to track a symbolic type_info
> object rather than tracking the originating expression.
>
> This is groundwork for supporting polymorphic typeid expressions. (Note
> that this somewhat regresses our support for DR1968, but it turns out
> that that never actually worked anyway, at least in non-trivial cases.)
>
> 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/APValue.h (original)
> +++ cfe/trunk/include/clang/AST/APValue.h Thu May 16 18:46:05 2019
> @@ -24,14 +24,52 @@ namespace clang {
> class AddrLabelExpr;
> class ASTContext;
> class CharUnits;
> + class CXXRecordDecl;
> + class Decl;
> class DiagnosticBuilder;
> class Expr;
> class FieldDecl;
> - class Decl;
> + struct PrintingPolicy;
> + class Type;
> 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]
> @@ -57,13 +95,18 @@ public:
>
> class LValueBase {
> public:
> - typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
> + typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue>
> + PtrTy;
>
> - LValueBase() : CallIndex(0), Version(0) {}
> + LValueBase() : Local{} {}
>
> template <class T>
> - LValueBase(T P, unsigned I = 0, unsigned V = 0)
> - : Ptr(P), CallIndex(I), Version(V) {}
> + 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);
>
> template <class T>
> bool is() const { return Ptr.is<T>(); }
> @@ -78,28 +121,15 @@ 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 {
> - return CallIndex;
> - }
> + unsigned getCallIndex() const;
> + unsigned getVersion() const;
> + QualType getTypeInfoType() const;
>
> - 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);
> friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) {
> return !(LHS == RHS);
> }
> @@ -107,7 +137,14 @@ public:
>
> private:
> PtrTy Ptr;
> - unsigned CallIndex, Version;
> + struct LocalState {
> + unsigned CallIndex, Version;
> + };
> + union {
> + LocalState Local;
> + /// The type std::type_info, if this is a TypeInfoLValue.
> + void *TypeInfoType;
> + };
> };
>
> /// 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu May 16 18:46:05 2019
> @@ -160,6 +160,9 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/APValue.cpp (original)
> +++ cfe/trunk/lib/AST/APValue.cpp Thu May 16 18:46:05 2019
> @@ -20,6 +20,56 @@
> #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;
> @@ -60,6 +110,8 @@ 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());
> }
> @@ -470,7 +522,9 @@ void APValue::printPretty(raw_ostream &O
>
> if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
> Out << *VD;
> - else {
> + else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
> + TI.print(Out, Ctx.getPrintingPolicy());
> + } else {
> assert(Base.get<const Expr *>() != nullptr &&
> "Expecting non-null Expr");
> Base.get<const Expr*>()->printPretty(Out, nullptr,
> @@ -495,6 +549,9 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ExprConstant.cpp (original)
> +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu May 16 18:46:05 2019
> @@ -87,6 +87,9 @@ 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
> @@ -1783,6 +1786,9 @@ 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:
> @@ -1800,7 +1806,6 @@ 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:
> @@ -1878,9 +1883,9 @@ static void NoteLValueLocation(EvalInfo
> const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
> if (VD)
> Info.Note(VD->getLocation(), diag::note_declared_at);
> - else
> - Info.Note(Base.get<const Expr*>()->getExprLoc(),
> - diag::note_constexpr_temporary_here);
> + 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.
> }
>
> /// Check that this reference or pointer core constant expression is a valid
> @@ -3404,7 +3409,7 @@ static CompleteObject findCompleteObject
>
> if (!Frame) {
> if (const MaterializeTemporaryExpr *MTE =
> - dyn_cast<MaterializeTemporaryExpr>(Base)) {
> + dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
> assert(MTE->getStorageDuration() == SD_Static &&
> "should have a frame for a non-global materialized temporary");
>
> @@ -3439,7 +3444,13 @@ static CompleteObject findCompleteObject
> } else {
> if (!IsAccess)
> return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
> - Info.FFDiag(E);
> + 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);
> return CompleteObject();
> }
> } else {
> @@ -5777,13 +5788,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
> @@ -6018,8 +6029,14 @@ LValueExprEvaluator::VisitCompoundLitera
> }
>
> bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
> - if (!E->isPotentiallyEvaluated())
> - return Success(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()));
> + }
>
> Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
> << E->getExprOperand()->getType()
> @@ -6615,9 +6632,11 @@ 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 = GetAlignOfExpr(
> - Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf);
> + BaseAlignment = GetAlignOfType(
> + Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
> }
>
> if (BaseAlignment < Align) {
> @@ -8335,6 +8354,10 @@ 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;
> @@ -8399,6 +8422,8 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Thu May 16 18:46:05 2019
> @@ -1735,6 +1735,17 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu May 16 18:46:05 2019
> @@ -6424,8 +6424,11 @@ ExprResult Sema::CheckTemplateArgument(N
> // -- a string literal
> // -- the result of a typeid expression, or
> // -- a predefined __func__ variable
> - if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
> - if (isa<CXXUuidofExpr>(E)) {
> + 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)) {
> Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
> break;
> }
> @@ -6433,8 +6436,6 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/test/CXX/drs/dr19xx.cpp (original)
> +++ cfe/trunk/test/CXX/drs/dr19xx.cpp Thu May 16 18:46:05 2019
> @@ -167,9 +167,14 @@ namespace dr1959 { // dr1959: 3.9
> #endif
> }
>
> -namespace dr1968 { // dr1968: yes
> +namespace dr1968 { // dr1968: no
> #if __cplusplus >= 201103L
> - static_assert(&typeid(int) == &typeid(int), ""); // expected-error{{not an integral constant expression}}
> + // 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(), "");
> #endif
> }
>
>
> Modified: cfe/trunk/test/Parser/MicrosoftExtensions.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/MicrosoftExtensions.cpp?rev=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/test/Parser/MicrosoftExtensions.cpp (original)
> +++ cfe/trunk/test/Parser/MicrosoftExtensions.cpp Thu May 16 18:46:05 2019
> @@ -138,6 +138,8 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/builtin-constant-p.cpp (original)
> +++ cfe/trunk/test/SemaCXX/builtin-constant-p.cpp Thu May 16 18:46:05 2019
> @@ -130,3 +130,8 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/typeid.cpp (original)
> +++ cfe/trunk/test/SemaCXX/typeid.cpp Thu May 16 18:46:05 2019
> @@ -6,7 +6,7 @@ void f()
> }
>
> namespace std {
> - class type_info;
> + struct type_info { const char *name; };
> }
>
> void g()
> @@ -27,3 +27,6 @@ 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=360974&r1=360973&r2=360974&view=diff
> ==============================================================================
> --- cfe/trunk/www/cxx_dr_status.html (original)
> +++ cfe/trunk/www/cxx_dr_status.html Thu May 16 18:46:05 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="full" align="center">Yes</td>
> + <td class="none" align="center">No</td>
> </tr>
> <tr class="open" id="1969">
> <td><a href="http://wg21.link/cwg1969">1969</a></td>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list