diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/APValue.cpp | 72 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 47 |
2 files changed, 101 insertions, 18 deletions
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<TypeInfoLValue>::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<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; @@ -45,21 +100,19 @@ APValue::LValueBase::operator bool () const { clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey(), - DenseMapInfo<unsigned>::getEmptyKey()); + DenseMapInfo<const ValueDecl*>::getEmptyKey()); } clang::APValue::LValueBase llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { return clang::APValue::LValueBase( - DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey(), - DenseMapInfo<unsigned>::getTombstoneKey()); + DenseMapInfo<const ValueDecl*>::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()); } @@ -470,7 +523,9 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ 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 +550,9 @@ 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"); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 29b6d12c2f2..e41264e55e4 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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::LValueBase B) { 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::LValueBase B) { 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 &Info, APValue::LValueBase Base) { 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(EvalInfo &Info, const Expr *E, 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(EvalInfo &Info, const Expr *E, } 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::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { } 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::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 = 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 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; @@ -8399,6 +8422,8 @@ 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(); |