forked from OSchip/llvm-project
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 7ee4307bd4
)
llvm-svn: 360988
This commit is contained in:
parent
a5a4124c49
commit
a971003e46
|
@ -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
|
||||
|
|
|
@ -160,9 +160,6 @@ def note_constexpr_access_static_temporary : Note<
|
|||
"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">;
|
||||
|
|
|
@ -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::LValueBase>::getTombstoneKey() {
|
|||
|
||||
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 &Out, ASTContext &Ctx, QualType Ty) const{
|
|||
|
||||
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 &Out, ASTContext &Ctx, QualType Ty) const{
|
|||
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");
|
||||
|
|
|
@ -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::LValueBase B) {
|
|||
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::LValueBase B) {
|
|||
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 &Info, APValue::LValueBase Base) {
|
|||
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(EvalInfo &Info, const Expr *E,
|
|||
|
||||
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(EvalInfo &Info, const Expr *E,
|
|||
} 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::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
|
|||
}
|
||||
|
||||
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::VisitBuiltinCallExpr(const CallExpr *E,
|
|||
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 EvaluateBuiltinConstantPForLValue(const APValue &LV) {
|
|||
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::LValueBase B) {
|
|||
} 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();
|
||||
|
|
|
@ -1735,17 +1735,6 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
|
|||
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*>());
|
||||
}
|
||||
|
|
|
@ -6424,11 +6424,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
// -- 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(NonTypeTemplateParmDecl *Param,
|
|||
<< 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() &&
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -138,8 +138,6 @@ typedef COM_CLASS_TEMPLATE_REF<struct_with_uuid, __uuidof(struct_with_uuid)> COM
|
|||
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@-1 {{read of object '__uuidof(struct_with_uuid)' whose value is not known}}
|
||||
// expected-note@-2 {{temporary created here}}
|
||||
|
||||
namespace PR16911 {
|
||||
struct __declspec(uuid("{12345678-1234-1234-1234-1234567890aB}")) uuid;
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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@+1 {{read of object 'typeid(int).name' whose value is not known}}
|
||||
constexpr const char *name = typeid(int).name; // expected-error {{constant expression}}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue