Skip to content

Commit 7ee4307

Browse files
committed
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.) llvm-svn: 360974
1 parent 457d7ca commit 7ee4307

File tree

11 files changed

+196
-47
lines changed

11 files changed

+196
-47
lines changed

clang/include/clang/AST/APValue.h

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,52 @@ namespace clang {
2424
class AddrLabelExpr;
2525
class ASTContext;
2626
class CharUnits;
27+
class CXXRecordDecl;
28+
class Decl;
2729
class DiagnosticBuilder;
2830
class Expr;
2931
class FieldDecl;
30-
class Decl;
32+
struct PrintingPolicy;
33+
class Type;
3134
class ValueDecl;
32-
class CXXRecordDecl;
33-
class QualType;
3435

36+
/// Symbolic representation of typeid(T) for some type T.
37+
class TypeInfoLValue {
38+
const Type *T;
39+
40+
public:
41+
TypeInfoLValue() : T() {}
42+
explicit TypeInfoLValue(const Type *T);
43+
44+
const Type *getType() const { return T; }
45+
explicit operator bool() const { return T; }
46+
47+
void *getOpaqueValue() { return const_cast<Type*>(T); }
48+
static TypeInfoLValue getFromOpaqueValue(void *Value) {
49+
TypeInfoLValue V;
50+
V.T = reinterpret_cast<const Type*>(Value);
51+
return V;
52+
}
53+
54+
void print(llvm::raw_ostream &Out, const PrintingPolicy &Policy) const;
55+
};
56+
}
57+
58+
namespace llvm {
59+
template<> struct PointerLikeTypeTraits<clang::TypeInfoLValue> {
60+
static void *getAsVoidPointer(clang::TypeInfoLValue V) {
61+
return V.getOpaqueValue();
62+
}
63+
static clang::TypeInfoLValue getFromVoidPointer(void *P) {
64+
return clang::TypeInfoLValue::getFromOpaqueValue(P);
65+
}
66+
// Validated by static_assert in APValue.cpp; hardcoded to avoid needing
67+
// to include Type.h.
68+
static constexpr int NumLowBitsAvailable = 3;
69+
};
70+
}
71+
72+
namespace clang {
3573
/// APValue - This class implements a discriminated union of [uninitialized]
3674
/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset],
3775
/// [Vector: N * APValue], [Array: N * APValue]
@@ -57,13 +95,18 @@ class APValue {
5795

5896
class LValueBase {
5997
public:
60-
typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
98+
typedef llvm::PointerUnion<const ValueDecl *, const Expr *, TypeInfoLValue>
99+
PtrTy;
61100

62-
LValueBase() : CallIndex(0), Version(0) {}
101+
LValueBase() : Local{} {}
63102

64103
template <class T>
65-
LValueBase(T P, unsigned I = 0, unsigned V = 0)
66-
: Ptr(P), CallIndex(I), Version(V) {}
104+
LValueBase(T P, unsigned I = 0, unsigned V = 0) : Ptr(P), Local{I, V} {
105+
assert(!is<TypeInfoLValue>() &&
106+
"don't use this constructor to form a type_info lvalue");
107+
}
108+
109+
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo);
67110

68111
template <class T>
69112
bool is() const { return Ptr.is<T>(); }
@@ -78,36 +121,30 @@ class APValue {
78121

79122
bool isNull() const;
80123

81-
explicit operator bool () const;
124+
explicit operator bool() const;
82125

83-
PtrTy getPointer() const {
84-
return Ptr;
85-
}
86-
87-
unsigned getCallIndex() const {
88-
return CallIndex;
89-
}
126+
PtrTy getPointer() const { return Ptr; }
90127

91-
void setCallIndex(unsigned Index) {
92-
CallIndex = Index;
93-
}
128+
unsigned getCallIndex() const;
129+
unsigned getVersion() const;
130+
QualType getTypeInfoType() const;
94131

95-
unsigned getVersion() const {
96-
return Version;
97-
}
98-
99-
friend bool operator==(const LValueBase &LHS, const LValueBase &RHS) {
100-
return LHS.Ptr == RHS.Ptr && LHS.CallIndex == RHS.CallIndex &&
101-
LHS.Version == RHS.Version;
102-
}
132+
friend bool operator==(const LValueBase &LHS, const LValueBase &RHS);
103133
friend bool operator!=(const LValueBase &LHS, const LValueBase &RHS) {
104134
return !(LHS == RHS);
105135
}
106136
friend llvm::hash_code hash_value(const LValueBase &Base);
107137

108138
private:
109139
PtrTy Ptr;
110-
unsigned CallIndex, Version;
140+
struct LocalState {
141+
unsigned CallIndex, Version;
142+
};
143+
union {
144+
LocalState Local;
145+
/// The type std::type_info, if this is a TypeInfoLValue.
146+
void *TypeInfoType;
147+
};
111148
};
112149

113150
/// A FieldDecl or CXXRecordDecl, along with a flag indicating whether we

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ def note_constexpr_access_static_temporary : Note<
160160
"dynamic_cast of}0 temporary "
161161
"is not allowed in a constant expression outside the expression that "
162162
"created the temporary">;
163+
def note_constexpr_access_unreadable_object : Note<
164+
"%select{read of|assignment to|increment of|decrement of|member call on|"
165+
"dynamic_cast of}0 object '%1' whose value is not known">;
163166
def note_constexpr_modify_global : Note<
164167
"a constant expression cannot modify an object that is visible outside "
165168
"that expression">;

clang/lib/AST/APValue.cpp

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,56 @@
2020
#include "llvm/Support/raw_ostream.h"
2121
using namespace clang;
2222

23+
/// The identity of a type_info object depends on the canonical unqualified
24+
/// type only.
25+
TypeInfoLValue::TypeInfoLValue(const Type *T)
26+
: T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
27+
28+
void TypeInfoLValue::print(llvm::raw_ostream &Out,
29+
const PrintingPolicy &Policy) const {
30+
Out << "typeid(";
31+
QualType(getType(), 0).print(Out, Policy);
32+
Out << ")";
33+
}
34+
35+
static_assert(
36+
1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
37+
alignof(const Type *),
38+
"Type is insufficiently aligned");
39+
40+
APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
41+
QualType TypeInfo) {
42+
LValueBase Base;
43+
Base.Ptr = LV;
44+
Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
45+
return Base;
46+
}
47+
48+
unsigned APValue::LValueBase::getCallIndex() const {
49+
return is<TypeInfoLValue>() ? 0 : Local.CallIndex;
50+
}
51+
52+
unsigned APValue::LValueBase::getVersion() const {
53+
return is<TypeInfoLValue>() ? 0 : Local.Version;
54+
}
55+
56+
QualType APValue::LValueBase::getTypeInfoType() const {
57+
assert(is<TypeInfoLValue>() && "not a type_info lvalue");
58+
return QualType::getFromOpaquePtr(TypeInfoType);
59+
}
60+
61+
namespace clang {
62+
bool operator==(const APValue::LValueBase &LHS,
63+
const APValue::LValueBase &RHS) {
64+
if (LHS.Ptr != RHS.Ptr)
65+
return false;
66+
if (LHS.is<TypeInfoLValue>())
67+
return true;
68+
return LHS.Local.CallIndex == RHS.Local.CallIndex &&
69+
LHS.Local.Version == RHS.Local.Version;
70+
}
71+
}
72+
2373
namespace {
2474
struct LVBase {
2575
APValue::LValueBase Base;
@@ -60,6 +110,8 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
60110

61111
namespace clang {
62112
llvm::hash_code hash_value(const APValue::LValueBase &Base) {
113+
if (Base.is<TypeInfoLValue>())
114+
return llvm::hash_value(Base.getOpaqueValue());
63115
return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
64116
Base.getVersion());
65117
}
@@ -470,7 +522,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
470522

471523
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
472524
Out << *VD;
473-
else {
525+
else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
526+
TI.print(Out, Ctx.getPrintingPolicy());
527+
} else {
474528
assert(Base.get<const Expr *>() != nullptr &&
475529
"Expecting non-null Expr");
476530
Base.get<const Expr*>()->printPretty(Out, nullptr,
@@ -495,6 +549,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
495549
if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
496550
Out << *VD;
497551
ElemTy = VD->getType();
552+
} else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
553+
TI.print(Out, Ctx.getPrintingPolicy());
554+
ElemTy = Base.getTypeInfoType();
498555
} else {
499556
const Expr *E = Base.get<const Expr*>();
500557
assert(E != nullptr && "Expecting non-null Expr");

clang/lib/AST/ExprConstant.cpp

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ namespace {
8787
return D->getType();
8888
}
8989

90+
if (TypeInfoLValue TI = B.dyn_cast<TypeInfoLValue>())
91+
return B.getTypeInfoType();
92+
9093
const Expr *Base = B.get<const Expr*>();
9194

9295
// For a materialized temporary, the type of the temporary we materialized
@@ -1783,6 +1786,9 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
17831786
return isa<FunctionDecl>(D);
17841787
}
17851788

1789+
if (B.is<TypeInfoLValue>())
1790+
return true;
1791+
17861792
const Expr *E = B.get<const Expr*>();
17871793
switch (E->getStmtClass()) {
17881794
default:
@@ -1800,7 +1806,6 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
18001806
case Expr::PredefinedExprClass:
18011807
case Expr::ObjCStringLiteralClass:
18021808
case Expr::ObjCEncodeExprClass:
1803-
case Expr::CXXTypeidExprClass:
18041809
case Expr::CXXUuidofExprClass:
18051810
return true;
18061811
case Expr::ObjCBoxedExprClass:
@@ -1878,9 +1883,9 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
18781883
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
18791884
if (VD)
18801885
Info.Note(VD->getLocation(), diag::note_declared_at);
1881-
else
1882-
Info.Note(Base.get<const Expr*>()->getExprLoc(),
1883-
diag::note_constexpr_temporary_here);
1886+
else if (const Expr *E = Base.dyn_cast<const Expr*>())
1887+
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
1888+
// We have no information to show for a typeid(T) object.
18841889
}
18851890

18861891
/// Check that this reference or pointer core constant expression is a valid
@@ -3404,7 +3409,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
34043409

34053410
if (!Frame) {
34063411
if (const MaterializeTemporaryExpr *MTE =
3407-
dyn_cast<MaterializeTemporaryExpr>(Base)) {
3412+
dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
34083413
assert(MTE->getStorageDuration() == SD_Static &&
34093414
"should have a frame for a non-global materialized temporary");
34103415

@@ -3439,7 +3444,13 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
34393444
} else {
34403445
if (!IsAccess)
34413446
return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
3442-
Info.FFDiag(E);
3447+
APValue Val;
3448+
LVal.moveInto(Val);
3449+
Info.FFDiag(E, diag::note_constexpr_access_unreadable_object)
3450+
<< AK
3451+
<< Val.getAsString(Info.Ctx,
3452+
Info.Ctx.getLValueReferenceType(LValType));
3453+
NoteLValueLocation(Info, LVal.Base);
34433454
return CompleteObject();
34443455
}
34453456
} else {
@@ -5777,13 +5788,13 @@ class LValueExprEvaluatorBase
57775788
// - Literals
57785789
// * CompoundLiteralExpr in C (and in global scope in C++)
57795790
// * StringLiteral
5780-
// * CXXTypeidExpr
57815791
// * PredefinedExpr
57825792
// * ObjCStringLiteralExpr
57835793
// * ObjCEncodeExpr
57845794
// * AddrLabelExpr
57855795
// * BlockExpr
57865796
// * CallExpr for a MakeStringConstant builtin
5797+
// - typeid(T) expressions, as TypeInfoLValues
57875798
// - Locals and temporaries
57885799
// * MaterializeTemporaryExpr
57895800
// * Any Expr, with a CallIndex indicating the function in which the temporary
@@ -6018,8 +6029,14 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
60186029
}
60196030

60206031
bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
6021-
if (!E->isPotentiallyEvaluated())
6022-
return Success(E);
6032+
if (!E->isPotentiallyEvaluated()) {
6033+
TypeInfoLValue TypeInfo;
6034+
if (E->isTypeOperand())
6035+
TypeInfo = TypeInfoLValue(E->getTypeOperand(Info.Ctx).getTypePtr());
6036+
else
6037+
TypeInfo = TypeInfoLValue(E->getExprOperand()->getType().getTypePtr());
6038+
return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
6039+
}
60236040

60246041
Info.FFDiag(E, diag::note_constexpr_typeid_polymorphic)
60256042
<< E->getExprOperand()->getType()
@@ -6615,9 +6632,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
66156632
if (const ValueDecl *VD =
66166633
OffsetResult.Base.dyn_cast<const ValueDecl*>()) {
66176634
BaseAlignment = Info.Ctx.getDeclAlign(VD);
6635+
} else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) {
6636+
BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf);
66186637
} else {
6619-
BaseAlignment = GetAlignOfExpr(
6620-
Info, OffsetResult.Base.get<const Expr *>(), UETT_AlignOf);
6638+
BaseAlignment = GetAlignOfType(
6639+
Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf);
66216640
}
66226641

66236642
if (BaseAlignment < Align) {
@@ -8335,6 +8354,10 @@ static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {
83358354
if (!isa<StringLiteral>(E))
83368355
return false;
83378356
return LV.getLValueOffset().isZero();
8357+
} else if (Base.is<TypeInfoLValue>()) {
8358+
// Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to
8359+
// evaluate to true.
8360+
return true;
83388361
} else {
83398362
// Any other base is not constant enough for GCC.
83408363
return false;
@@ -8399,6 +8422,8 @@ static QualType getObjectType(APValue::LValueBase B) {
83998422
} else if (const Expr *E = B.get<const Expr*>()) {
84008423
if (isa<CompoundLiteralExpr>(E))
84018424
return E->getType();
8425+
} else if (B.is<TypeInfoLValue>()) {
8426+
return B.getTypeInfoType();
84028427
}
84038428

84048429
return QualType();

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1735,6 +1735,17 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
17351735
return nullptr;
17361736
}
17371737

1738+
// Handle typeid(T).
1739+
if (TypeInfoLValue TI = base.dyn_cast<TypeInfoLValue>()) {
1740+
llvm::Type *StdTypeInfoPtrTy =
1741+
CGM.getTypes().ConvertType(base.getTypeInfoType())->getPointerTo();
1742+
llvm::Constant *TypeInfo =
1743+
CGM.GetAddrOfRTTIDescriptor(QualType(TI.getType(), 0));
1744+
if (TypeInfo->getType() != StdTypeInfoPtrTy)
1745+
TypeInfo = llvm::ConstantExpr::getBitCast(TypeInfo, StdTypeInfoPtrTy);
1746+
return TypeInfo;
1747+
}
1748+
17381749
// Otherwise, it must be an expression.
17391750
return Visit(base.get<const Expr*>());
17401751
}

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6424,17 +6424,18 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
64246424
// -- a string literal
64256425
// -- the result of a typeid expression, or
64266426
// -- a predefined __func__ variable
6427-
if (auto *E = Value.getLValueBase().dyn_cast<const Expr*>()) {
6428-
if (isa<CXXUuidofExpr>(E)) {
6427+
APValue::LValueBase Base = Value.getLValueBase();
6428+
auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>());
6429+
if (Base && !VD) {
6430+
auto *E = Base.dyn_cast<const Expr *>();
6431+
if (E && isa<CXXUuidofExpr>(E)) {
64296432
Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts());
64306433
break;
64316434
}
64326435
Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref)
64336436
<< Arg->getSourceRange();
64346437
return ExprError();
64356438
}
6436-
auto *VD = const_cast<ValueDecl *>(
6437-
Value.getLValueBase().dyn_cast<const ValueDecl *>());
64386439
// -- a subobject
64396440
if (Value.hasLValuePath() && Value.getLValuePath().size() == 1 &&
64406441
VD && VD->getType()->isArrayType() &&

0 commit comments

Comments
 (0)