From ee0ce302c5eb4f26738f334f2fd8b165fa65dfca Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 17 May 2019 07:06:46 +0000 Subject: 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.) This reinstates r360974, reverted in r360988, with a fix for a static_assert failure on 32-bit builds: force Type base class to have 8-byte alignment like the rest of Clang's AST nodes. llvm-svn: 360995 --- clang/lib/AST/APValue.cpp | 72 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 7 deletions(-) (limited to 'clang/lib/AST/APValue.cpp') diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index e7902e68780..249c382f893 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -20,6 +20,61 @@ #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::NumLowBitsAvailable <= + alignof(const Type *), + "Type is insufficiently aligned"); + +APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} +APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V) + : Ptr(P), Local{I, V} {} + +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() ? 0 : Local.CallIndex; +} + +unsigned APValue::LValueBase::getVersion() const { + return is() ? 0 : Local.Version; +} + +QualType APValue::LValueBase::getTypeInfoType() const { + assert(is() && "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()) + return true; + return LHS.Local.CallIndex == RHS.Local.CallIndex && + LHS.Local.Version == RHS.Local.Version; +} +} + namespace { struct LVBase { APValue::LValueBase Base; @@ -45,21 +100,19 @@ APValue::LValueBase::operator bool () const { clang::APValue::LValueBase llvm::DenseMapInfo::getEmptyKey() { return clang::APValue::LValueBase( - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey(), - DenseMapInfo::getEmptyKey()); + DenseMapInfo::getEmptyKey()); } clang::APValue::LValueBase llvm::DenseMapInfo::getTombstoneKey() { return clang::APValue::LValueBase( - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey(), - DenseMapInfo::getTombstoneKey()); + DenseMapInfo::getTombstoneKey()); } namespace clang { llvm::hash_code hash_value(const APValue::LValueBase &Base) { + if (Base.is()) + return llvm::hash_value(Base.getOpaqueValue()); return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), Base.getVersion()); } @@ -470,7 +523,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast()) Out << *VD; - else { + else if (TypeInfoLValue TI = Base.dyn_cast()) { + TI.print(Out, Ctx.getPrintingPolicy()); + } else { assert(Base.get() != nullptr && "Expecting non-null Expr"); Base.get()->printPretty(Out, nullptr, @@ -495,6 +550,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ if (const ValueDecl *VD = Base.dyn_cast()) { Out << *VD; ElemTy = VD->getType(); + } else if (TypeInfoLValue TI = Base.dyn_cast()) { + TI.print(Out, Ctx.getPrintingPolicy()); + ElemTy = Base.getTypeInfoType(); } else { const Expr *E = Base.get(); assert(E != nullptr && "Expecting non-null Expr"); -- cgit v1.2.3