diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/APValue.cpp | 13 | ||||
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 380 |
2 files changed, 118 insertions, 275 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index e7902e68780..9ed756d9d84 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -58,16 +58,13 @@ llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() { DenseMapInfo<unsigned>::getTombstoneKey()); } -namespace clang { -llvm::hash_code hash_value(const APValue::LValueBase &Base) { - return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(), - Base.getVersion()); -} -} - unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue( const clang::APValue::LValueBase &Base) { - return hash_value(Base); + llvm::FoldingSetNodeID ID; + ID.AddPointer(Base.getOpaqueValue()); + ID.AddInteger(Base.getCallIndex()); + ID.AddInteger(Base.getVersion()); + return ID.ComputeHash(); } bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual( diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 77f65337dde..0c86ec65744 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -213,7 +213,7 @@ namespace { // The order of this enum is important for diagnostics. enum CheckSubobjectKind { CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex, - CSK_Real, CSK_Imag + CSK_This, CSK_Real, CSK_Imag }; /// A path from a glvalue to a subobject of that glvalue. @@ -622,40 +622,6 @@ namespace { } }; - /// A reference to an object whose construction we are currently evaluating. - struct ObjectUnderConstruction { - APValue::LValueBase Base; - ArrayRef<APValue::LValuePathEntry> Path; - friend bool operator==(const ObjectUnderConstruction &LHS, - const ObjectUnderConstruction &RHS) { - return LHS.Base == RHS.Base && LHS.Path == RHS.Path; - } - friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) { - return llvm::hash_combine(Obj.Base, Obj.Path); - } - }; - enum class ConstructionPhase { None, Bases, AfterBases }; -} - -namespace llvm { -template<> struct DenseMapInfo<ObjectUnderConstruction> { - using Base = DenseMapInfo<APValue::LValueBase>; - static ObjectUnderConstruction getEmptyKey() { - return {Base::getEmptyKey(), {}}; } - static ObjectUnderConstruction getTombstoneKey() { - return {Base::getTombstoneKey(), {}}; - } - static unsigned getHashValue(const ObjectUnderConstruction &Object) { - return hash_value(Object); - } - static bool isEqual(const ObjectUnderConstruction &LHS, - const ObjectUnderConstruction &RHS) { - return LHS == RHS; - } -}; -} - -namespace { /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information /// about the AST context, but also maintains information about the folded @@ -706,35 +672,32 @@ namespace { /// declaration whose initializer is being evaluated, if any. APValue *EvaluatingDeclValue; - /// Set of objects that are currently being constructed. - llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase> - ObjectsUnderConstruction; + /// EvaluatingObject - Pair of the AST node that an lvalue represents and + /// the call index that that lvalue was allocated in. + typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>> + EvaluatingObject; + + /// EvaluatingConstructors - Set of objects that are currently being + /// constructed. + llvm::DenseSet<EvaluatingObject> EvaluatingConstructors; struct EvaluatingConstructorRAII { EvalInfo &EI; - ObjectUnderConstruction Object; + EvaluatingObject Object; bool DidInsert; - EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object, - bool HasBases) + EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object) : EI(EI), Object(Object) { - DidInsert = - EI.ObjectsUnderConstruction - .insert({Object, HasBases ? ConstructionPhase::Bases - : ConstructionPhase::AfterBases}) - .second; - } - void finishedConstructingBases() { - EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases; + DidInsert = EI.EvaluatingConstructors.insert(Object).second; } ~EvaluatingConstructorRAII() { - if (DidInsert) EI.ObjectsUnderConstruction.erase(Object); + if (DidInsert) EI.EvaluatingConstructors.erase(Object); } }; - ConstructionPhase - isEvaluatingConstructor(APValue::LValueBase Base, - ArrayRef<APValue::LValuePathEntry> Path) { - return ObjectsUnderConstruction.lookup({Base, Path}); + bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex, + unsigned Version) { + return EvaluatingConstructors.count( + EvaluatingObject(Decl, {CallIndex, Version})); } /// If we're currently speculatively evaluating, the outermost call stack @@ -823,6 +786,7 @@ namespace { void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) { EvaluatingDecl = Base; EvaluatingDeclValue = &Value; + EvaluatingConstructors.insert({Base, {0, 0}}); } const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); } @@ -1326,22 +1290,14 @@ void EvalInfo::addCallStack(unsigned Limit) { } } -/// Kinds of access we can perform on an object, for diagnostics. Note that -/// we consider a member function call to be a kind of access, even though -/// it is not formally an access of the object, because it has (largely) the -/// same set of semantic restrictions. +/// Kinds of access we can perform on an object, for diagnostics. enum AccessKinds { AK_Read, AK_Assign, AK_Increment, - AK_Decrement, - AK_MemberCall, + AK_Decrement }; -static bool isModification(AccessKinds AK) { - return AK != AK_Read && AK != AK_MemberCall; -} - namespace { struct ComplexValue { private: @@ -2828,73 +2784,28 @@ static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E, return false; } -static bool lifetimeStartedInEvaluation(EvalInfo &Info, - APValue::LValueBase Base) { - // A temporary we created. - if (Base.getCallIndex()) - return true; - - auto *Evaluating = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>(); - if (!Evaluating) - return false; - - // The variable whose initializer we're evaluating. - if (auto *BaseD = Base.dyn_cast<const ValueDecl*>()) - if (declaresSameEntity(Evaluating, BaseD)) - return true; - - // A temporary lifetime-extended by the variable whose initializer we're - // evaluating. - if (auto *BaseE = Base.dyn_cast<const Expr *>()) - if (auto *BaseMTE = dyn_cast<MaterializeTemporaryExpr>(BaseE)) - if (declaresSameEntity(BaseMTE->getExtendingDecl(), Evaluating)) - return true; - - return false; -} - namespace { /// A handle to a complete object (an object that is not a subobject of /// another object). struct CompleteObject { - /// The identity of the object. - APValue::LValueBase Base; /// The value of the complete object. APValue *Value; /// The type of the complete object. QualType Type; + bool LifetimeStartedInEvaluation; CompleteObject() : Value(nullptr) {} - CompleteObject(APValue::LValueBase Base, APValue *Value, QualType Type) - : Base(Base), Value(Value), Type(Type) {} - - bool mayReadMutableMembers(EvalInfo &Info) const { - // In C++14 onwards, it is permitted to read a mutable member whose - // lifetime began within the evaluation. - // FIXME: Should we also allow this in C++11? - if (!Info.getLangOpts().CPlusPlus14) - return false; - return lifetimeStartedInEvaluation(Info, Base); + CompleteObject(APValue *Value, QualType Type, + bool LifetimeStartedInEvaluation) + : Value(Value), Type(Type), + LifetimeStartedInEvaluation(LifetimeStartedInEvaluation) { + assert(Value && "missing value for complete object"); } - explicit operator bool() const { return !Type.isNull(); } + explicit operator bool() const { return Value; } }; } // end anonymous namespace -static QualType getSubobjectType(QualType ObjType, QualType SubobjType, - bool IsMutable = false) { - // C++ [basic.type.qualifier]p1: - // - A const object is an object of type const T or a non-mutable subobject - // of a const object. - if (ObjType.isConstQualified() && !IsMutable) - SubobjType.addConst(); - // - A volatile object is an object of type const T or a subobject of a - // volatile object. - if (ObjType.isVolatileQualified()) - SubobjType.addVolatile(); - return SubobjType; -} - /// Find the designated sub-object of an rvalue. template<typename SubobjectHandler> typename SubobjectHandler::result_type @@ -2917,78 +2828,31 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, APValue *O = Obj.Value; QualType ObjType = Obj.Type; const FieldDecl *LastField = nullptr; - const FieldDecl *VolatileField = nullptr; + const bool MayReadMutableMembers = + Obj.LifetimeStartedInEvaluation && Info.getLangOpts().CPlusPlus14; // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { if (O->isUninit()) { if (!Info.checkingPotentialConstantExpression()) - Info.FFDiag(E, diag::note_constexpr_access_uninit) - << handler.AccessKind; + Info.FFDiag(E, diag::note_constexpr_access_uninit) << handler.AccessKind; return handler.failed(); } - // C++ [class.ctor]p5: - // const and volatile semantics are not applied on an object under - // construction. - if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) && - ObjType->isRecordType() && - Info.isEvaluatingConstructor( - Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(), - Sub.Entries.begin() + I)) != - ConstructionPhase::None) { - ObjType = Info.Ctx.getCanonicalType(ObjType); - ObjType.removeLocalConst(); - ObjType.removeLocalVolatile(); - } - - // If this is our last pass, check that the final object type is OK. - if (I == N || (I == N - 1 && ObjType->isAnyComplexType())) { - // Accesses to volatile objects are prohibited. - if (ObjType.isVolatileQualified() && - handler.AccessKind != AK_MemberCall) { - if (Info.getLangOpts().CPlusPlus) { - int DiagKind; - SourceLocation Loc; - const NamedDecl *Decl = nullptr; - if (VolatileField) { - DiagKind = 2; - Loc = VolatileField->getLocation(); - Decl = VolatileField; - } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) { - DiagKind = 1; - Loc = VD->getLocation(); - Decl = VD; - } else { - DiagKind = 0; - if (auto *E = Obj.Base.dyn_cast<const Expr *>()) - Loc = E->getExprLoc(); - } - Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) - << handler.AccessKind << DiagKind << Decl; - Info.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind; - } else { - Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); - } - return handler.failed(); - } - + if (I == N) { // If we are reading an object of class type, there may still be more // things we need to check: if there are any mutable subobjects, we // cannot perform this read. (This only happens when performing a trivial // copy or assignment.) if (ObjType->isRecordType() && handler.AccessKind == AK_Read && - !Obj.mayReadMutableMembers(Info) && - diagnoseUnreadableFields(Info, E, ObjType)) + !MayReadMutableMembers && diagnoseUnreadableFields(Info, E, ObjType)) return handler.failed(); - } - if (I == N) { if (!handler.found(*O, ObjType)) return false; // If we modified a bit-field, truncate it to the right width. - if (isModification(handler.AccessKind) && + if (handler.AccessKind != AK_Read && LastField && LastField->isBitField() && !truncateBitfieldValue(Info, E, *O, LastField)) return false; @@ -3034,8 +2898,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, return handler.failed(); } - ObjType = getSubobjectType( - ObjType, ObjType->castAs<ComplexType>()->getElementType()); + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = ObjType->castAs<ComplexType>()->getElementType(); + if (WasConstQualified) + ObjType.addConst(); assert(I == N - 1 && "extracting subobject of scalar?"); if (O->isComplexInt()) { @@ -3047,8 +2913,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, : O->getComplexFloatReal(), ObjType); } } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. + // FIXME: Should we also allow this in C++11? if (Field->isMutable() && handler.AccessKind == AK_Read && - !Obj.mayReadMutableMembers(Info)) { + !MayReadMutableMembers) { Info.FFDiag(E, diag::note_constexpr_ltor_mutable, 1) << Field; Info.Note(Field->getLocation(), diag::note_declared_at); @@ -3069,17 +2938,34 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } else O = &O->getStructField(Field->getFieldIndex()); - ObjType = getSubobjectType(ObjType, Field->getType(), Field->isMutable()); + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = Field->getType(); + if (WasConstQualified && !Field->isMutable()) + ObjType.addConst(); + + if (ObjType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + // FIXME: Include a description of the path to the volatile subobject. + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) + << handler.AccessKind << 2 << Field; + Info.Note(Field->getLocation(), diag::note_declared_at); + } else { + Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + } + return handler.failed(); + } + LastField = Field; - if (Field->getType().isVolatileQualified()) - VolatileField = Field; } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); O = &O->getStructBase(getBaseIndex(Derived, Base)); - ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base)); + bool WasConstQualified = ObjType.isConstQualified(); + ObjType = Info.Ctx.getRecordType(Base); + if (WasConstQualified) + ObjType.addConst(); } } } @@ -3260,7 +3146,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // is not a constant expression (even if the object is non-volatile). We also // apply this rule to C++98, in order to conform to the expected 'volatile' // semantics. - if (AK != AK_MemberCall && LValType.isVolatileQualified()) { + if (LValType.isVolatileQualified()) { if (Info.getLangOpts().CPlusPlus) Info.FFDiag(E, diag::note_constexpr_access_volatile_type) << AK << LValType; @@ -3269,16 +3155,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, return CompleteObject(); } - // The wording is unclear on this, but for the purpose of determining the - // validity of a member function call, we assume that all objects whose - // lifetimes did not start within the constant evaluation are in fact within - // their lifetimes, so member calls on them are valid. (This simultaneously - // includes all members of a union!) - bool NeedValue = AK != AK_MemberCall; - // Compute value storage location and type of base object. APValue *BaseVal = nullptr; QualType BaseType = getType(LVal.Base); + bool LifetimeStartedInEvaluation = Frame; if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) { // In C++98, const, non-volatile integers initialized with ICEs are ICEs. @@ -3298,29 +3178,37 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, return CompleteObject(); } + // Accesses of volatile-qualified objects are not allowed. + if (BaseType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 1 << VD; + Info.Note(VD->getLocation(), diag::note_declared_at); + } else { + Info.FFDiag(E); + } + return CompleteObject(); + } + // Unless we're looking at a local variable or argument in a constexpr call, // the variable we're reading must be const. if (!Frame) { if (Info.getLangOpts().CPlusPlus14 && - declaresSameEntity( - VD, Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) { + VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) { // OK, we can read and modify an object if we're in the process of // evaluating its initializer, because its lifetime began in this // evaluation. - } else if (isModification(AK)) { - // All the remaining cases do not permit modification of the object. + } else if (AK != AK_Read) { + // All the remaining cases only permit reading. Info.FFDiag(E, diag::note_constexpr_modify_global); return CompleteObject(); } else if (VD->isConstexpr()) { // OK, we can read this variable. } else if (BaseType->isIntegralOrEnumerationType()) { - // In OpenCL if a variable is in constant address space it is a const - // value. + // In OpenCL if a variable is in constant address space it is a const value. if (!(BaseType.isConstQualified() || (Info.getLangOpts().OpenCL && BaseType.getAddressSpace() == LangAS::opencl_constant))) { - if (!NeedValue) - return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); if (Info.getLangOpts().CPlusPlus) { Info.FFDiag(E, diag::note_constexpr_ltor_non_const_int, 1) << VD; Info.Note(VD->getLocation(), diag::note_declared_at); @@ -3329,8 +3217,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, } return CompleteObject(); } - } else if (!NeedValue) { - return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); } else if (BaseType->isFloatingType() && BaseType.isConstQualified()) { // We support folding of const floating-point types, in order to make // static const data members of such types (supported as an extension) @@ -3390,8 +3276,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!(BaseType.isConstQualified() && BaseType->isIntegralOrEnumerationType()) && !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) { - if (!NeedValue) - return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); Info.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here); return CompleteObject(); @@ -3399,9 +3283,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); assert(BaseVal && "got reference to unevaluated temporary"); + LifetimeStartedInEvaluation = true; } else { - if (!NeedValue) - return CompleteObject(LVal.getLValueBase(), nullptr, BaseType); Info.FFDiag(E); return CompleteObject(); } @@ -3409,6 +3292,29 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion()); assert(BaseVal && "missing value for temporary"); } + + // Volatile temporary objects cannot be accessed in constant expressions. + if (BaseType.isVolatileQualified()) { + if (Info.getLangOpts().CPlusPlus) { + Info.FFDiag(E, diag::note_constexpr_access_volatile_obj, 1) + << AK << 0; + Info.Note(Base->getExprLoc(), diag::note_constexpr_temporary_here); + } else { + Info.FFDiag(E); + } + return CompleteObject(); + } + } + + // During the construction of an object, it is not yet 'const'. + // FIXME: This doesn't do quite the right thing for const subobjects of the + // object under construction. + if (Info.isEvaluatingConstructor(LVal.getLValueBase(), + LVal.getLValueCallIndex(), + LVal.getLValueVersion())) { + BaseType = Info.Ctx.getCanonicalType(BaseType); + BaseType.removeLocalConst(); + LifetimeStartedInEvaluation = true; } // In C++14, we can't safely access any mutable state when we might be @@ -3418,10 +3324,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, // to be read here (but take care with 'mutable' fields). if ((Frame && Info.getLangOpts().CPlusPlus14 && Info.EvalStatus.HasSideEffects) || - (isModification(AK) && Depth < Info.SpeculativeEvaluationDepth)) + (AK != AK_Read && Depth < Info.SpeculativeEvaluationDepth)) return CompleteObject(); - return CompleteObject(LVal.getLValueBase(), BaseVal, BaseType); + return CompleteObject(BaseVal, BaseType, LifetimeStartedInEvaluation); } /// Perform an lvalue-to-rvalue conversion on the given glvalue. This @@ -3455,7 +3361,7 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, APValue Lit; if (!Evaluate(Lit, Info, CLE->getInitializer())) return false; - CompleteObject LitObj(LVal.Base, &Lit, Base->getType()); + CompleteObject LitObj(&Lit, Base->getType(), false); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { // Special-case character extraction so we don't have to construct an @@ -4501,48 +4407,6 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; } -namespace { -struct CheckMemberCallThisPointerHandler { - static const AccessKinds AccessKind = AK_MemberCall; - typedef bool result_type; - bool failed() { return false; } - bool found(APValue &Subobj, QualType SubobjType) { return true; } - bool found(APSInt &Value, QualType SubobjType) { return true; } - bool found(APFloat &Value, QualType SubobjType) { return true; } -}; -} // end anonymous namespace - -const AccessKinds CheckMemberCallThisPointerHandler::AccessKind; - -/// Check that the pointee of the 'this' pointer in a member function call is -/// either within its lifetime or in its period of construction or destruction. -static bool checkMemberCallThisPointer(EvalInfo &Info, const Expr *E, - const LValue &This) { - CompleteObject Obj = - findCompleteObject(Info, E, AK_MemberCall, This, QualType()); - - if (!Obj) - return false; - - if (!Obj.Value) { - // The object is not usable in constant expressions, so we can't inspect - // its value to see if it's in-lifetime or what the active union members - // are. We can still check for a one-past-the-end lvalue. - if (This.Designator.isOnePastTheEnd() || - This.Designator.isMostDerivedAnUnsizedArray()) { - Info.FFDiag(E, This.Designator.isOnePastTheEnd() - ? diag::note_constexpr_access_past_end - : diag::note_constexpr_access_unsized_array) - << AK_MemberCall; - return false; - } - return true; - } - - CheckMemberCallThisPointerHandler Handler; - return Obj && findSubobject(Info, E, Obj, This.Designator, Handler); -} - /// Determine if a class has any fields that might need to be copied by a /// trivial copy or move operation. static bool hasFields(const CXXRecordDecl *RD) { @@ -4656,9 +4520,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, } EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, - ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries}, - RD->getNumBases()); + Info, {This.getLValueBase(), + {This.getLValueCallIndex(), This.getLValueVersion()}}); CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues); // FIXME: Creating an APValue just to hold a nonexistent return value is @@ -4732,11 +4595,6 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, BaseType->getAsCXXRecordDecl(), &Layout)) return false; Value = &Result.getStructBase(BasesSeen++); - - // This is the point at which the dynamic type of the object becomes this - // class type. - if (BasesSeen == RD->getNumBases()) - EvalObj.finishedConstructingBases(); } else if ((FD = I->getMember())) { if (!HandleLValueMember(Info, I->getInit(), Subobject, FD, &Layout)) return false; @@ -5127,7 +4985,7 @@ public: } else return Error(E); - if (This && !checkMemberCallThisPointer(Info, E, *This)) + if (This && !This->checkSubobject(Info, E, CSK_This)) return false; const FunctionDecl *Definition = nullptr; @@ -5163,8 +5021,6 @@ public: /// A member expression where the object is a prvalue is itself a prvalue. bool VisitMemberExpr(const MemberExpr *E) { - assert(!Info.Ctx.getLangOpts().CPlusPlus11 && - "missing temporary materialization conversion"); assert(!E->isArrow() && "missing call to bound member function?"); APValue Val; @@ -5179,10 +5035,7 @@ public: assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); - // Note: there is no lvalue base here. But this case should only ever - // happen in C or in C++98, where we cannot be evaluating a constexpr - // constructor, which is the only case the base matters. - CompleteObject Obj(APValue::LValueBase(), &Val, BaseTy); + CompleteObject Obj(&Val, BaseTy, true); SubobjectDesignator Designator(BaseTy); Designator.addDeclUnchecked(FD); @@ -6776,12 +6629,6 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); - auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); - - EvalInfo::EvaluatingConstructorRAII EvalObj( - Info, - ObjectUnderConstruction{This.getLValueBase(), This.Designator.Entries}, - CXXRD && CXXRD->getNumBases()); if (RD->isUnion()) { const FieldDecl *Field = E->getInitializedFieldInUnion(); @@ -6808,6 +6655,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr); } + auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); if (Result.isUninit()) Result = APValue(APValue::UninitStruct(), CXXRD ? CXXRD->getNumBases() : 0, std::distance(RD->field_begin(), RD->field_end())); @@ -6815,7 +6663,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool Success = true; // Initialize base classes. - if (CXXRD && CXXRD->getNumBases()) { + if (CXXRD) { for (const auto &Base : CXXRD->bases()) { assert(ElementNo < E->getNumInits() && "missing init for base class"); const Expr *Init = E->getInit(ElementNo); @@ -6832,8 +6680,6 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } ++ElementNo; } - - EvalObj.finishedConstructingBases(); } // Initialize members. |