llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-modules Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> --- Patch is 27.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/204289.diff 18 Files Affected: - (modified) clang/include/clang/AST/APValue.h (+23-5) - (modified) clang/include/clang/AST/PropertiesBase.td (+10-1) - (modified) clang/lib/AST/APValue.cpp (+26-4) - (modified) clang/lib/AST/ASTImporter.cpp (+4-2) - (modified) clang/lib/AST/ByteCode/Compiler.cpp (+38-7) - (modified) clang/lib/AST/ByteCode/Interp.cpp (+3) - (modified) clang/lib/AST/ByteCode/Interp.h (+8) - (modified) clang/lib/AST/ByteCode/Opcodes.td (+6) - (modified) clang/lib/AST/ByteCode/Pointer.cpp (+2-2) - (modified) clang/lib/AST/DeclCXX.cpp (+3-2) - (modified) clang/lib/AST/ExprConstant.cpp (+35-10) - (modified) clang/lib/AST/TextNodeDumper.cpp (+6) - (modified) clang/lib/Sema/SemaDeclCXX.cpp (+3-6) - (modified) clang/lib/Sema/SemaType.cpp (+1-1) - (modified) clang/test/AST/ByteCode/cxx23.cpp (-1) - (added) clang/test/AST/ByteCode/virtual-bases.cpp (+133) - (modified) clang/test/CXX/drs/cwg16xx.cpp (+14-2) - (modified) clang/test/CXX/drs/cwg6xx.cpp (+12) ``````````diff diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index acbd922ba5319..c509addfe5d48 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -297,7 +297,8 @@ class APValue { APValue *Elts; unsigned NumBases; unsigned NumFields; - StructData(unsigned NumBases, unsigned NumFields); + unsigned NumVirtualBases; + StructData(unsigned NumBases, unsigned NumFields, unsigned NumVirtualBases); StructData(const StructData &) = delete; StructData &operator=(const StructData &) = delete; ~StructData(); @@ -418,10 +419,13 @@ class APValue { /// \param UninitStruct Marker. Pass an empty UninitStruct. /// \param NumBases Number of bases. /// \param NumMembers Number of members. - APValue(UninitStruct, unsigned NumBases, unsigned NumMembers) + /// \param NumVirtualBases Number of virtual bases. + APValue(UninitStruct, unsigned NumBases, unsigned NumMembers, + unsigned NumVirtualBases = 0) : Kind(None), AllowConstexprUnknown(false) { - MakeStruct(NumBases, NumMembers); + MakeStruct(NumBases, NumMembers, NumVirtualBases); } + /// Creates a new union APValue. /// \param ActiveDecl The FieldDecl of the active union member. /// \param ActiveValue The value of the active union member. @@ -659,6 +663,10 @@ class APValue { assert(isStruct() && "Invalid accessor"); return ((const StructData *)(const char *)&Data)->NumFields; } + unsigned getStructNumVirtualBases() const { + assert(isStruct() && "Invalid accessor"); + return ((const StructData *)(const char *)&Data)->NumVirtualBases; + } APValue &getStructBase(unsigned i) { assert(isStruct() && "Invalid accessor"); assert(i < getStructNumBases() && "base class index OOB"); @@ -669,12 +677,21 @@ class APValue { assert(i < getStructNumFields() && "field index OOB"); return ((StructData *)(char *)&Data)->Elts[getStructNumBases() + i]; } + APValue &getStructVirtualBase(unsigned i) { + assert(isStruct() && "Invalid accessor"); + assert(i < getStructNumVirtualBases() && "base class index OOB"); + return ((StructData *)(char *)&Data) + ->Elts[getStructNumBases() + getStructNumFields() + i]; + } const APValue &getStructBase(unsigned i) const { return const_cast<APValue*>(this)->getStructBase(i); } const APValue &getStructField(unsigned i) const { return const_cast<APValue*>(this)->getStructField(i); } + const APValue &getStructVirtualBase(unsigned i) const { + return const_cast<APValue *>(this)->getStructVirtualBase(i); + } const FieldDecl *getUnionField() const { assert(isUnion() && "Invalid accessor"); @@ -788,11 +805,12 @@ class APValue { } void MakeLValue(); void MakeArray(unsigned InitElts, unsigned Size); - void MakeStruct(unsigned B, unsigned M) { + void MakeStruct(unsigned B, unsigned M, unsigned V) { assert(isAbsent() && "Bad state change"); - new ((void *)(char *)&Data) StructData(B, M); + new ((void *)(char *)&Data) StructData(B, M, V); Kind = Struct; } + void MakeUnion() { assert(isAbsent() && "Bad state change"); new ((void *)(char *)&Data) UnionData(); diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index fd3cce10be303..25ef4c26a9aa1 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -416,6 +416,10 @@ let Class = PropertyTypeCase<APValue, "Struct"> in { unsigned numFields = node.getStructNumFields(); for (unsigned i = 0; i < numFields; ++i) structFields.push_back(node.getStructField(i)); + SmallVector<APValue, 4> structVirtualBases; + unsigned numVirtualBases = node.getStructNumVirtualBases(); + for (unsigned i = 0; i < numVirtualBases; ++i) + structVirtualBases.push_back(node.getStructVirtualBase(i)); }]>; def : Property<"bases", Array<APValue>> { let Read = [{ structBases }]; @@ -423,13 +427,18 @@ let Class = PropertyTypeCase<APValue, "Struct"> in { def : Property<"fields", Array<APValue>> { let Read = [{ structFields }]; } + def : Property<"vbases", Array<APValue>> { + let Read = [{ structVirtualBases }]; + } def : Creator<[{ APValue result; - result.MakeStruct(bases.size(), fields.size()); + result.MakeStruct(bases.size(), fields.size(), vbases.size()); for (unsigned i = 0; i < bases.size(); ++i) result.getStructBase(i) = bases[i]; for (unsigned i = 0; i < fields.size(); ++i) result.getStructField(i) = fields[i]; + for (unsigned i = 0; i < vbases.size(); ++i) + result.getStructVirtualBase(i) = vbases[i]; return result; }]>; } diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index fd51584f564bb..727e5f8c00a10 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -282,9 +282,12 @@ APValue::Arr::Arr(unsigned NumElts, unsigned Size) : NumElts(NumElts), ArrSize(Size) {} APValue::Arr::~Arr() { delete [] Elts; } -APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) : - Elts(new APValue[NumBases+NumFields]), - NumBases(NumBases), NumFields(NumFields) {} +APValue::StructData::StructData(unsigned NumBases, unsigned NumFields, + unsigned NumVirtualBases) + : Elts(new APValue[NumBases + NumFields + NumVirtualBases]), + NumBases(NumBases), NumFields(NumFields), + NumVirtualBases(NumVirtualBases) {} + APValue::StructData::~StructData() { delete [] Elts; } @@ -349,11 +352,14 @@ APValue::APValue(const APValue &RHS) getArrayFiller() = RHS.getArrayFiller(); break; case Struct: - MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields()); + MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields(), + RHS.getStructNumVirtualBases()); for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I) getStructBase(I) = RHS.getStructBase(I); for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I) getStructField(I) = RHS.getStructField(I); + for (unsigned I = 0, N = RHS.getStructNumVirtualBases(); I != N; ++I) + getStructVirtualBase(I) = RHS.getStructVirtualBase(I); break; case Union: MakeUnion(); @@ -503,6 +509,8 @@ void APValue::Profile(llvm::FoldingSetNodeID &ID) const { getStructBase(I).Profile(ID); for (unsigned I = 0, N = getStructNumFields(); I != N; ++I) getStructField(I).Profile(ID); + for (unsigned I = 0, N = getStructNumVirtualBases(); I != N; ++I) + getStructVirtualBase(I).Profile(ID); return; case Union: @@ -942,6 +950,17 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, printPretty(Out, Policy, FI->getType(), Ctx); First = false; } + if (unsigned N = getStructNumVirtualBases()) { + const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); + CXXRecordDecl::base_class_const_iterator BI = CD->vbases_begin(); + for (unsigned I = 0; I != N; ++I, ++BI) { + assert(BI != CD->vbases_end()); + if (!First) + Out << ", "; + getStructVirtualBase(I).printPretty(Out, Policy, BI->getType(), Ctx); + First = false; + } + } Out << '}'; return; } @@ -1172,6 +1191,9 @@ LinkageInfo LinkageComputer::getLVForValue(const APValue &V, for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) if (Merge(V.getStructField(I))) break; + for (unsigned I = 0, N = V.getStructNumVirtualBases(); I != N; ++I) + if (Merge(V.getStructVirtualBase(I))) + break; break; } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 567d2d07298a3..9d38b02218bc2 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -10694,11 +10694,13 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) { break; case APValue::Struct: Result.MakeStruct(FromValue.getStructNumBases(), - FromValue.getStructNumFields()); + FromValue.getStructNumFields(), + FromValue.getStructNumVirtualBases()); ImportLoop( ((const APValue::StructData *)(const char *)&FromValue.Data)->Elts, ((const APValue::StructData *)(const char *)&Result.Data)->Elts, - FromValue.getStructNumBases() + FromValue.getStructNumFields()); + FromValue.getStructNumBases() + FromValue.getStructNumFields() + + FromValue.getStructNumVirtualBases()); break; case APValue::Union: { Result.MakeUnion(); diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 638e6ecafb295..1b7e8ea6948a3 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -4861,7 +4861,14 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R, return false; } - // FIXME: Virtual bases. + for (const Record::Base &B : R->virtual_bases()) { + if (!this->emitGetPtrVirtBase(cast<CXXRecordDecl>(B.R->getDecl()), E)) + return false; + if (!this->visitZeroRecordInitializer(B.R, E)) + return false; + if (!this->emitFinishInitPop(E)) + return false; + } return true; } @@ -5517,11 +5524,25 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, if (Val.isStruct()) { const Record *R = this->getRecord(T); assert(R); + + // Bases. + for (unsigned I = 0, N = Val.getStructNumBases(); I != N; ++I) { + const APValue &B = Val.getStructBase(I); + const Record::Base *RB = R->getBase(I); + QualType BaseType = Ctx.getASTContext().getCanonicalTagType(RB->Decl); + + if (!this->emitGetPtrBase(RB->Offset, E)) + return false; + if (!this->visitAPValueInitializer(B, E, BaseType)) + return false; + if (!this->emitFinishInitPop(E)) + return false; + } + for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) { const APValue &F = Val.getStructField(I); const Record::Field *RF = R->getField(I); QualType FieldType = RF->Decl->getType(); - // Fields. if (OptPrimType PT = classify(FieldType)) { if (!this->visitAPValue(F, *PT, E)) @@ -5538,13 +5559,13 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val, } } - // Bases. - for (unsigned I = 0, N = Val.getStructNumBases(); I != N; ++I) { - const APValue &B = Val.getStructBase(I); - const Record::Base *RB = R->getBase(I); + // Virtual Bases. + for (unsigned I = 0, N = Val.getStructNumVirtualBases(); I != N; ++I) { + const APValue &B = Val.getStructVirtualBase(I); + const Record::Base *RB = R->getVirtualBase(I); QualType BaseType = Ctx.getASTContext().getCanonicalTagType(RB->Decl); - if (!this->emitGetPtrBase(RB->Offset, E)) + if (!this->emitGetPtrVirtBase(cast<CXXRecordDecl>(RB->R->getDecl()), E)) return false; if (!this->visitAPValueInitializer(B, E, BaseType)) return false; @@ -7098,6 +7119,16 @@ bool Compiler<Emitter>::compileDestructor(const CXXDestructorDecl *Dtor) { return false; } + for (const Record::Base &Base : llvm::reverse(R->virtual_bases())) { + if (Base.R->hasTrivialDtor()) + continue; + if (!this->emitGetPtrVirtBase(cast<CXXRecordDecl>(Base.R->getDecl()), + SourceInfo{})) + return false; + if (!this->emitRecordDestructionPop(Base.R, {})) + return false; + } + if (!this->emitMarkDestroyed(Dtor)) return false; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index e5bf9c0c590ac..f61468079f7aa 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1623,6 +1623,9 @@ static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func, if (!D->ElemRecord) return true; + if (S.getLangOpts().CPlusPlus26) + return true; + if (D->ElemRecord->getNumVirtualBases() == 0) return true; diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 0f9e585e19769..4beda945c1a14 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2182,6 +2182,14 @@ inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, return VirtBaseHelper(S, OpPC, D, Ptr); } +inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { + assert(D); + const Pointer &Ptr = S.Stk.peek<Pointer>(); + if (!CheckNull(S, OpPC, Ptr, CSK_Base)) + return false; + return VirtBaseHelper(S, OpPC, D, Ptr); +} + inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { assert(D); diff --git a/clang/lib/AST/ByteCode/Opcodes.td b/clang/lib/AST/ByteCode/Opcodes.td index e350d7b2e547d..39a164dd52718 100644 --- a/clang/lib/AST/ByteCode/Opcodes.td +++ b/clang/lib/AST/ByteCode/Opcodes.td @@ -383,6 +383,12 @@ def GetPtrVirtBasePop : Opcode { // RecordDecl of base class. let Args = [ArgRecordDecl]; } +def GetPtrVirtBase : Opcode { + // RecordDecl of base class. + let Args = [ArgRecordDecl]; +} + + // [] -> [Pointer] def GetPtrThisBase : Opcode { // Offset of field, which is a base. diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp index 96cd8bb9e11c2..ddcd21c504b2a 100644 --- a/clang/lib/AST/ByteCode/Pointer.cpp +++ b/clang/lib/AST/ByteCode/Pointer.cpp @@ -847,7 +847,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, unsigned NB = Record->getNumBases(); unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases(); - R = APValue(APValue::UninitStruct(), NB, NF); + R = APValue(APValue::UninitStruct(), NB, NF, NV); for (unsigned I = 0; I != NF; ++I) { const Record::Field *FD = Record->getField(I); @@ -875,7 +875,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx, QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(VD->Decl); PtrView VP = Ptr.atField(VD->Offset); - Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); + Ok &= Composite(VirtBaseTy, VP, R.getStructVirtualBase(I)); } } return Ok; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index ce4ba971a4631..82510ad885af8 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -335,8 +335,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // In the definition of a constexpr function [...] // -- if the function is a constructor or destructor, // its class shall not have any virtual base classes - data().DefaultedDefaultConstructorIsConstexpr = false; - data().DefaultedDestructorIsConstexpr = false; + data().DefaultedDefaultConstructorIsConstexpr = + C.getLangOpts().CPlusPlus26; + data().DefaultedDestructorIsConstexpr = C.getLangOpts().CPlusPlus26; // C++1z [class.copy]p8: // The implicitly-declared copy constructor for a class X will have diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index bc98c0d86bb65..1d4b463ddd10a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -2472,6 +2472,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { + if (BS.isVirtual()) + continue; const APValue &BaseValue = Value.getStructBase(BaseIndex); if (!BaseValue.hasValue()) { SourceLocation TypeBeginLoc = BS.getBaseTypeLoc(); @@ -5443,7 +5445,8 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E, /// Get the value to use for a default-initialized object of type T. /// Return false if it encounters something invalid. -static bool handleDefaultInitValue(QualType T, APValue &Result) { +static bool handleDefaultInitValue(QualType T, APValue &Result, + bool Toplevel = true) { bool Success = true; // If there is already a value present don't overwrite it. @@ -5459,22 +5462,44 @@ static bool handleDefaultInitValue(QualType T, APValue &Result) { Result = APValue((const FieldDecl *)nullptr); return true; } - Result = - APValue(APValue::UninitStruct(), RD->getNumBases(), RD->getNumFields()); + + // bases() includes directlys specified virtual bases as well. + unsigned NonVirtualBases = + llvm::count_if(RD->bases(), [](auto &B) { return !B.isVirtual(); }); + Result = APValue(APValue::UninitStruct(), NonVirtualBases, + RD->getNumFields(), Toplevel ? RD->getNumVBases() : 0); unsigned Index = 0; - for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + for (CXXRecordDecl::base_class_const_iterator B = RD->bases_begin(), End = RD->bases_end(); - I != End; ++I, ++Index) - Success &= - handleDefaultInitValue(I->getType(), Result.getStructBase(Index)); + B != End; ++B) { + if (B->isVirtual()) + continue; + Success &= handleDefaultInitValue(B->getType(), + Result.getStructBase(Index), false); + ++Index; + } for (const auto *I : RD->fields()) { if (I->isUnnamedBitField()) continue; Success &= handleDefaultInitValue( - I->getType(), Result.getStructField(I->getFieldIndex())); + I->getType(), Result.getStructField(I->getFieldIndex()), false); } + + if (Toplevel) { + Index = 0; + + for (const auto &B : RD->vbases()) { + Success &= handleDefaultInitValue( + B.getType(), Result.getStructVirtualBase(Index), false); + ++Index; + } + } else { + // Virtual bases should only exist at the top level of an APValue. + assert(Result.getStructNumVirtualBases() == 0); + } + return Success; } @@ -5482,8 +5507,8 @@ static bool handleDefaultInitValue(QualType T, APValue &Result) { dyn_cast_or_null<ConstantArrayType>(T->getAsArrayTypeUnsafe())) { Result = APValue(APValue::UninitArray(), 0, AT->getZExtSize()); if (Result.hasArrayFiller()) - Success &= - handleDefaultInitValue(AT->getElementType(), Result.getArrayFiller()); + Success &= handleDefaultInitValue(AT->getElementType(), + Result.getArrayFiller(), false); return Success; } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 2b1c0cac25b6d..8d758609727ad 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -811,6 +811,12 @@ void TextNodeDumper::Visit(const APValue &Value, QualType Ty) { }, Value.getStructNumFields(), "field", "fields"); + dumpAPValueChildren( + Value, Ty, + [](const APValue &Value, unsigned Index) -> const APValue & { + return Value.getStructVirtualBase(Index); + }, + Value.getStructNumVirtualBases(), "vbase", "vbases"); return; } case APValue::Matrix: { diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 418ff01f3d98a..a699b7a465e4c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1944,7 +1944,7 @@ static bool CheckConstexprMissingReturn(Sema &SemaRef, const FunctionDecl *Dcl); bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, CheckConstexprKind Kind) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD); - if (MD && MD->isInstance()) { + if (!getLangOpts().CPlusPlus26 && MD && MD->isInstance()) { // C++11 [dcl.constexpr]p4: // The definition of a constexpr constructor shall satisfy the following // constraints: @@ -2473,8 +2473,6 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, } } else if (!Constructor->isDependentContext() && !Constructor->isDelegatingConstructor()) { - assert(RD... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/204289 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
