diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -204,26 +204,55 @@ /// mean a virtual or non-virtual base class subobject. typedef llvm::PointerIntPair BaseOrMemberType; - /// A non-discriminated union of a base, field, or array index. + /// A discriminated union of a base, field, or array index. class LValuePathEntry { - static_assert(sizeof(uintptr_t) <= sizeof(uint64_t), - "pointer doesn't fit in 64 bits?"); - uint64_t Value; + enum class Kind { + Base, + VirtualBase, + Field, + Index + }; + llvm::PointerIntPair Value; public: LValuePathEntry() : Value() {} - LValuePathEntry(BaseOrMemberType BaseOrMember); + LValuePathEntry(const CXXRecordDecl *Base, bool Virtual); + LValuePathEntry(const FieldDecl *Field); + LValuePathEntry(size_t Index); static LValuePathEntry ArrayIndex(uint64_t Index) { - LValuePathEntry Result; - Result.Value = Index; - return Result; + return LValuePathEntry(static_cast(Index)); + } + static LValuePathEntry Declaration(const Decl *D, bool Virtual); + + bool isBase() const { return Value.getInt() == Kind::Base; } + bool isVirtualBase() const { return Value.getInt() == Kind::VirtualBase; } + bool isAnyBase() const { return isBase() || isVirtualBase(); } + bool isField() const { return Value.getInt() == Kind::Field; } + bool isArrayIndex() const { return Value.getInt() == Kind::Index; } + + const CXXRecordDecl *getAsBase() const { + assert(isAnyBase() && "Not a base class"); + return static_cast(Value.getPointer()); + } + const FieldDecl *getAsField() const { + assert(isField() && "Not a field"); + return static_cast(Value.getPointer()); + } + uint64_t getAsArrayIndex() const { + assert((Value.getInt() == Kind::Index) && "Not an index"); + return reinterpret_cast(Value.getOpaqueValue()) >> 2; + } + const Decl *getAsBaseOrMember() const { + assert((isAnyBase() || isField()) && "Not a declaration"); + return static_cast(Value.getPointer()); } - BaseOrMemberType getAsBaseOrMember() const { - return BaseOrMemberType::getFromOpaqueValue( - reinterpret_cast(Value)); + const CXXRecordDecl *getAsBaseOrNull() const { + return isAnyBase() ? getAsBase() : nullptr; + } + const FieldDecl *getAsFieldOrNull() const { + return isField() ? getAsField() : nullptr; } - uint64_t getAsArrayIndex() const { return Value; } void Profile(llvm::FoldingSetNodeID &ID) const; @@ -234,7 +263,7 @@ return A.Value != B.Value; } friend llvm::hash_code hash_value(LValuePathEntry A) { - return llvm::hash_value(A.Value); + return llvm::hash_value(A.Value.getOpaqueValue()); } }; class LValuePathSerializationHelper { diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -194,14 +194,16 @@ unsigned pathLength = asImpl().readUInt32(); for (unsigned i = 0; i < pathLength; ++i) { if (elemTy->template getAs()) { - unsigned int_ = asImpl().readUInt32(); - Decl *decl = asImpl().template readDeclAs(); - if (auto *recordDecl = dyn_cast(decl)) - elemTy = getASTContext().getRecordType(recordDecl); - else - elemTy = cast(decl)->getType(); - path.push_back( - APValue::LValuePathEntry(APValue::BaseOrMemberType(decl, int_))); + unsigned IsVirtualBase = asImpl().readUInt32(); + Decl *D = asImpl().template readDeclAs(); + if (auto *RD = dyn_cast(D)) { + elemTy = getASTContext().getRecordType(RD); + path.push_back(APValue::LValuePathEntry(RD, IsVirtualBase)); + } else { + auto FD = cast(D); + elemTy = FD->getType(); + path.push_back(APValue::LValuePathEntry(FD)); + } } else { elemTy = getASTContext().getAsArrayType(elemTy)->getElementType(); path.push_back( diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -181,15 +181,15 @@ auto &ctx = ((BasicWriterBase *)this)->getASTContext(); for (auto elem : path) { if (elemTy->getAs()) { - asImpl().writeUInt32(elem.getAsBaseOrMember().getInt()); - const Decl *baseOrMember = elem.getAsBaseOrMember().getPointer(); - if (const auto *recordDecl = dyn_cast(baseOrMember)) { - asImpl().writeDeclRef(recordDecl); - elemTy = ctx.getRecordType(recordDecl); - } else { - const auto *valueDecl = cast(baseOrMember); - asImpl().writeDeclRef(valueDecl); - elemTy = valueDecl->getType(); + asImpl().writeUInt32(elem.isVirtualBase()); + if (elem.isAnyBase()) { + const CXXRecordDecl *D = elem.getAsBase(); + asImpl().writeDeclRef(D); + elemTy = ctx.getRecordType(D); + } else if (elem.isField()) { + const FieldDecl *D = elem.getAsField(); + asImpl().writeDeclRef(D); + elemTy = D->getType(); } } else { asImpl().writeUInt32(elem.getAsArrayIndex()); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -144,14 +144,28 @@ } } -APValue::LValuePathEntry::LValuePathEntry(BaseOrMemberType BaseOrMember) { - if (const Decl *D = BaseOrMember.getPointer()) - BaseOrMember.setPointer(D->getCanonicalDecl()); - Value = reinterpret_cast(BaseOrMember.getOpaqueValue()); +APValue::LValuePathEntry::LValuePathEntry(const CXXRecordDecl *Base, + bool Virtual) { + Value.setPointerAndInt(Base, Virtual ? Kind::VirtualBase : Kind::Base); +} + +APValue::LValuePathEntry::LValuePathEntry(const FieldDecl *Field) { + Value.setPointerAndInt(Field, Kind::Field); +} + +APValue::LValuePathEntry::LValuePathEntry(size_t Index) { + Value.setPointerAndInt(reinterpret_cast(Index << 2), Kind::Index); +} + +APValue::LValuePathEntry APValue::LValuePathEntry::Declaration(const Decl *D, + bool Virtual) { + if (auto RD = dyn_cast(D)) + return LValuePathEntry(RD, Virtual); + return LValuePathEntry(cast(D)); } void APValue::LValuePathEntry::Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(Value); + ID.AddPointer(Value.getOpaqueValue()); } APValue::LValuePathSerializationHelper::LValuePathSerializationHelper( @@ -761,13 +775,12 @@ if (ElemTy->isRecordType()) { // The lvalue refers to a class type, so the next path entry is a base // or member. - const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); - if (const CXXRecordDecl *RD = dyn_cast(BaseOrMember)) { + if (const CXXRecordDecl *RD = Path[I].getAsBaseOrNull()) { CastToBase = RD; // Leave ElemTy referring to the most-derived class. The actual type // doesn't matter except for array types. } else { - const ValueDecl *VD = cast(BaseOrMember); + const FieldDecl *VD = Path[I].getAsField(); Out << "."; if (CastToBase) Out << *CastToBase << "::"; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9269,17 +9269,20 @@ FromValue.getLValuePath(); for (unsigned LoopIdx = 0; LoopIdx < PathLength; LoopIdx++) { if (FromElemTy->isRecordType()) { - const Decl *FromDecl = - FromPath[LoopIdx].getAsBaseOrMember().getPointer(); + const Decl *FromDecl = FromPath[LoopIdx].getAsBaseOrMember(); const Decl *ImpDecl = importChecked(Err, FromDecl); if (Err) return std::move(Err); - if (auto *RD = dyn_cast(FromDecl)) + if (auto *RD = dyn_cast(FromDecl)) { FromElemTy = Importer.FromContext.getRecordType(RD); - else + ToPath[LoopIdx] = + APValue::LValuePathEntry(cast(ImpDecl), + FromPath[LoopIdx].isVirtualBase()); + } else { FromElemTy = cast(FromDecl)->getType(); - ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType( - ImpDecl, FromPath[LoopIdx].getAsBaseOrMember().getInt())); + ToPath[LoopIdx] = + APValue::LValuePathEntry(cast(ImpDecl)); + } } else { FromElemTy = Importer.FromContext.getAsArrayType(FromElemTy)->getElementType(); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -82,22 +82,6 @@ return B.getType(); } - /// Get an LValue path entry, which is known to not be an array index, as a - /// field declaration. - static const FieldDecl *getAsField(APValue::LValuePathEntry E) { - return dyn_cast_or_null(E.getAsBaseOrMember().getPointer()); - } - /// Get an LValue path entry, which is known to not be an array index, as a - /// base class declaration. - static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) { - return dyn_cast_or_null(E.getAsBaseOrMember().getPointer()); - } - /// Determine whether this LValue path entry for a base class names a virtual - /// base class. - static bool isVirtualBaseClass(APValue::LValuePathEntry E) { - return E.getAsBaseOrMember().getInt(); - } - /// Given an expression, determine the type used to store the result of /// evaluating that expression. static QualType getStorageType(const ASTContext &Ctx, const Expr *E) { @@ -218,7 +202,7 @@ ArraySize = 2; MostDerivedLength = I + 1; IsArray = true; - } else if (const FieldDecl *FD = getAsField(Path[I])) { + } else if (const FieldDecl *FD = Path[I].getAsFieldOrNull()) { Type = FD->getType(); ArraySize = 0; MostDerivedLength = I + 1; @@ -384,7 +368,7 @@ assert(!Invalid && "invalid designator has no subobject type"); return MostDerivedPathLength == Entries.size() ? MostDerivedType - : Ctx.getRecordType(getAsBaseClass(Entries.back())); + : Ctx.getRecordType(Entries.back().getAsBase()); } /// Update this designator to refer to the first element within this array. @@ -413,7 +397,7 @@ /// Update this designator to refer to the given base or member of this /// object. void addDeclUnchecked(const Decl *D, bool Virtual = false) { - Entries.push_back(APValue::BaseOrMemberType(D, Virtual)); + Entries.push_back(APValue::LValuePathEntry::Declaration(D, Virtual)); // If this isn't a base class, it's a new most-derived object. if (const FieldDecl *FD = dyn_cast(D)) { @@ -3038,8 +3022,8 @@ for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) { if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); - const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]); - if (isVirtualBaseClass(D.Entries[I])) + const CXXRecordDecl *Base = D.Entries[I].getAsBase(); + if (D.Entries[I].isVirtualBase()) Result.Offset -= Layout.getVBaseClassOffset(Base); else Result.Offset -= Layout.getBaseClassOffset(Base); @@ -3741,7 +3725,7 @@ return handler.found(Index ? O->getComplexFloatImag() : O->getComplexFloatReal(), ObjType); } - } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) { + } else if (const FieldDecl *Field = Sub.Entries[I].getAsFieldOrNull()) { if (Field->isMutable() && !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) { Info.FFDiag(E, diag::note_constexpr_access_mutable, 1) @@ -3780,7 +3764,7 @@ } else { // Next subobject is a base class. const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl(); - const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]); + const CXXRecordDecl *Base = Sub.Entries[I].getAsBase(); O = &O->getStructBase(getBaseIndex(Derived, Base)); ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base)); @@ -3906,7 +3890,7 @@ WasArrayIndex = false; return I; } - if (const FieldDecl *FD = getAsField(A.Entries[I])) + if (const FieldDecl *FD = A.Entries[I].getAsFieldOrNull()) // Next subobject is a field. ObjType = FD->getType(); else @@ -4621,8 +4605,8 @@ unsigned PathLengthToMember = LV.Designator.Entries.size() - MemPtr.Path.size(); for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) { - const CXXRecordDecl *LVDecl = getAsBaseClass( - LV.Designator.Entries[PathLengthToMember + I]); + const CXXRecordDecl *LVDecl = + LV.Designator.Entries[PathLengthToMember + I].getAsBase(); const CXXRecordDecl *MPDecl = MemPtr.Path[I]; if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) { Info.FFDiag(RHS); @@ -4719,7 +4703,7 @@ if (NewEntriesSize == D.MostDerivedPathLength) FinalType = D.MostDerivedType->getAsCXXRecordDecl(); else - FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]); + FinalType = D.Entries[NewEntriesSize - 1].getAsBase(); if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) { Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) << D.MostDerivedType << TargetQT; @@ -5574,7 +5558,7 @@ Designator.Entries.size() && "invalid path length"); return (PathLength == Designator.MostDerivedPathLength) ? Designator.MostDerivedType->getAsCXXRecordDecl() - : getAsBaseClass(Designator.Entries[PathLength - 1]); + : Designator.Entries[PathLength - 1].getAsBase(); } /// Determine the dynamic type of an object. @@ -5918,9 +5902,8 @@ E = ME->getBase(); --PathLength; - assert(declaresSameEntity(FD, - LHS.Designator.Entries[PathLength] - .getAsBaseOrMember().getPointer())); + assert(declaresSameEntity( + FD, LHS.Designator.Entries[PathLength].getAsBaseOrMember())); // -- If E is of the form A[B] and is interpreted as a built-in array // subscripting operator, S(E) is [S(the array operand, if any)]. @@ -5945,9 +5928,9 @@ for (const CXXBaseSpecifier *Elt : llvm::reverse(ICE->path())) { --PathLength; (void)Elt; - assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(), - LHS.Designator.Entries[PathLength] - .getAsBaseOrMember().getPointer())); + assert( + declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(), + LHS.Designator.Entries[PathLength].getAsBase())); } // -- Otherwise, S(E) is empty. @@ -11255,13 +11238,13 @@ if (Index != 1) return false; BaseType = CT->getElementType(); - } else if (auto *FD = getAsField(Entry)) { + } else if (auto *FD = Entry.getAsFieldOrNull()) { bool Invalid; if (!IsLastOrInvalidFieldDecl(FD, Invalid)) return Invalid; BaseType = FD->getType(); } else { - assert(getAsBaseClass(Entry) && "Expecting cast to a base class"); + assert(Entry.getAsBase() && "Expecting cast to a base class"); return false; } } @@ -12697,18 +12680,20 @@ // constant expression. if (!WasArrayIndex && Mismatch < LHSDesignator.Entries.size() && Mismatch < RHSDesignator.Entries.size()) { - const FieldDecl *LF = getAsField(LHSDesignator.Entries[Mismatch]); - const FieldDecl *RF = getAsField(RHSDesignator.Entries[Mismatch]); + const FieldDecl *LF = + LHSDesignator.Entries[Mismatch].getAsFieldOrNull(); + const FieldDecl *RF = + RHSDesignator.Entries[Mismatch].getAsFieldOrNull(); if (!LF && !RF) Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_classes); else if (!LF) Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) - << getAsBaseClass(LHSDesignator.Entries[Mismatch]) - << RF->getParent() << RF; + << LHSDesignator.Entries[Mismatch].getAsBase() << RF->getParent() + << RF; else if (!RF) Info.CCEDiag(E, diag::note_constexpr_pointer_comparison_base_field) - << getAsBaseClass(RHSDesignator.Entries[Mismatch]) - << LF->getParent() << LF; + << RHSDesignator.Entries[Mismatch].getAsBase() << LF->getParent() + << LF; else if (!LF->getParent()->isUnion() && LF->getAccess() != RF->getAccess()) Info.CCEDiag(E, diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -116,8 +116,8 @@ // Create a path entry for the field. Descriptor *Desc = Ptr.getFieldDesc(); - if (auto *BaseOrMember = Desc->asDecl()) { - Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); + if (auto *D = Desc->asDecl()) { + Path.push_back(APValue::LValuePathEntry::Declaration(D, IsVirtual)); Ptr = Ptr.getBase(); continue; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -5376,12 +5376,10 @@ for (APValue::LValuePathEntry E : LV.getLValuePath()) { if (const ArrayType *AT = Ctx.getAsArrayType(T)) T = AT->getElementType(); - else if (const FieldDecl *FD = - dyn_cast(E.getAsBaseOrMember().getPointer())) + else if (const FieldDecl *FD = E.getAsFieldOrNull()) T = FD->getType(); else - T = Ctx.getRecordType( - cast(E.getAsBaseOrMember().getPointer())); + T = Ctx.getRecordType(E.getAsBase()); } return T; } @@ -5682,8 +5680,7 @@ OnePastTheEnd |= CAT->getSize() == E.getAsArrayIndex(); TypeSoFar = AT->getElementType(); } else { - const Decl *D = E.getAsBaseOrMember().getPointer(); - if (auto *FD = dyn_cast(D)) { + if (const FieldDecl *FD = E.getAsFieldOrNull()) { // ::= _ if (FD->getParent()->isUnion()) { Out << '_'; @@ -5692,7 +5689,7 @@ } TypeSoFar = FD->getType(); } else { - TypeSoFar = Ctx.getRecordType(cast(D)); + TypeSoFar = Ctx.getRecordType(E.getAsBase()); } } } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1722,8 +1722,7 @@ if (T->isArrayType()) goto mangling_unknown; - const Decl *D = E.getAsBaseOrMember().getPointer(); - auto *FD = dyn_cast(D); + const FieldDecl *FD = E.getAsFieldOrNull(); // We don't know how to mangle derived-to-base conversions yet. if (!FD) goto mangling_unknown; @@ -1739,10 +1738,8 @@ Out << "E"; mangle(VD); - for (APValue::LValuePathEntry E : V.getLValuePath()) { - const Decl *D = E.getAsBaseOrMember().getPointer(); - mangleUnqualifiedName(cast(D)); - } + for (APValue::LValuePathEntry E : V.getLValuePath()) + mangleUnqualifiedName(E.getAsField()); for (unsigned I = 0; I != NumAts; ++I) Out << '@'; }