diff options
-rw-r--r-- | clang/include/clang/AST/APValue.h | 91 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticASTKinds.td | 3 | ||||
-rw-r--r-- | clang/lib/AST/APValue.cpp | 59 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 47 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 9 | ||||
-rw-r--r-- | clang/test/CXX/drs/dr19xx.cpp | 9 | ||||
-rw-r--r-- | clang/test/Parser/MicrosoftExtensions.cpp | 2 | ||||
-rw-r--r-- | clang/test/SemaCXX/builtin-constant-p.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaCXX/typeid.cpp | 5 | ||||
-rwxr-xr-x | clang/www/cxx_dr_status.html | 2 |
11 files changed, 196 insertions, 47 deletions
diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index d266473..a6b0fc5 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -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; - } - - unsigned getCallIndex() const { - return CallIndex; - } + PtrTy getPointer() const { return Ptr; } - void setCallIndex(unsigned Index) { - CallIndex = Index; - } + unsigned getCallIndex() const; + unsigned getVersion() const; + QualType getTypeInfoType() const; - 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 diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 17256fb..3e9ebbb 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -160,6 +160,9 @@ 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">; diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index e7902e68..83b0fb5 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -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::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()); } @@ -470,7 +522,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 +549,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 29b6d12..e41264e 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(); diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index dd71cf0..70904b1 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1735,6 +1735,17 @@ 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*>()); } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index b9d3ff8..239b4ae 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6424,8 +6424,11 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- 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(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() && diff --git a/clang/test/CXX/drs/dr19xx.cpp b/clang/test/CXX/drs/dr19xx.cpp index a1e8c76..4e359681 100644 --- a/clang/test/CXX/drs/dr19xx.cpp +++ b/clang/test/CXX/drs/dr19xx.cpp @@ -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 } diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp index 63e8b60..913645b 100644 --- a/clang/test/Parser/MicrosoftExtensions.cpp +++ b/clang/test/Parser/MicrosoftExtensions.cpp @@ -138,6 +138,8 @@ 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; diff --git a/clang/test/SemaCXX/builtin-constant-p.cpp b/clang/test/SemaCXX/builtin-constant-p.cpp index 21cbaf7..f70676d 100644 --- a/clang/test/SemaCXX/builtin-constant-p.cpp +++ b/clang/test/SemaCXX/builtin-constant-p.cpp @@ -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))); diff --git a/clang/test/SemaCXX/typeid.cpp b/clang/test/SemaCXX/typeid.cpp index 48fcce0..4e696de 100644 --- a/clang/test/SemaCXX/typeid.cpp +++ b/clang/test/SemaCXX/typeid.cpp @@ -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@+1 {{read of object 'typeid(int).name' whose value is not known}} +constexpr const char *name = typeid(int).name; // expected-error {{constant expression}} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 6592e83..663fe58 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -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> |