llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) <details> <summary>Changes</summary> The previous code did not consider that the base class we're getting might not be on the path from `TypePtr` to `TypePtr.stripBaseCasts()` at all, because of multiple bases. --- Full diff: https://github.com/llvm/llvm-project/pull/207722.diff 5 Files Affected: - (modified) clang/lib/AST/ByteCode/Interp.cpp (+35-8) - (modified) clang/lib/AST/ByteCode/Pointer.h (+13-5) - (modified) clang/test/AST/ByteCode/cxx20.cpp (+1-2) - (modified) clang/test/AST/ByteCode/cxx2a.cpp (+33) - (modified) clang/test/CXX/dcl.decl/dcl.init/dcl.init.general/p16-cxx20.cpp (+1) ``````````diff diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 7884aa5b5b745..fcd2e9a10f625 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1939,19 +1939,46 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, return true; } -static bool getDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr, +static bool getDynamicDecl(InterpState &S, CodePtr OpPC, PtrView TypePtr, const CXXRecordDecl *&DynamicDecl) { - TypePtr = TypePtr.stripBaseCasts(); + + if (S.InitializingPtrs.empty()) { + TypePtr = TypePtr.stripBaseCasts(); + } else { + auto depth = [](PtrView V) -> unsigned { + unsigned C = 1; + while (!V.isRoot()) { + ++C; + V = V.getBase(); + } + return C; + }; + // Consider a 'normal' diamond hierarchy: + // A A 3 + // | | + // B C 2 + // \ / + // \ / + // D 1 + // When we use a pointer of D*, cast it to B's A* and + // use it during the construction of C*, the expected + // dynamic type is B. + PtrView InitPtr = S.InitializingPtrs.back(); + assert(depth(TypePtr) >= depth(InitPtr)); + unsigned D = depth(TypePtr) - depth(InitPtr); + for (unsigned I = 0; I != D; ++I) + TypePtr = TypePtr.getBase(); + } QualType DynamicType = TypePtr.getType(); - if (TypePtr.isStatic() || TypePtr.isConst()) { - if (const VarDecl *VD = TypePtr.getRootVarDecl(); + if (TypePtr.Pointee->isStatic() || TypePtr.isConst()) { + if (const VarDecl *VD = Pointer(TypePtr).getRootVarDecl(); VD && !VD->isConstexpr()) { const Expr *E = S.Current->getExpr(OpPC); - APValue V = TypePtr.toAPValue(S.getASTContext()); + APValue V = Pointer(TypePtr).toAPValue(S.getASTContext()); QualType TT = S.getASTContext().getLValueReferenceType(DynamicType); S.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type) - << AccessKinds::AK_MemberCall << V.getAsString(S.getASTContext(), TT); + << AK_MemberCall << V.getAsString(S.getASTContext(), TT); return false; } } @@ -2186,7 +2213,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, const FunctionDecl *Callee = Func->getDecl(); const CXXRecordDecl *DynamicDecl = nullptr; - if (!getDynamicDecl(S, OpPC, ThisPtr, DynamicDecl)) + if (!getDynamicDecl(S, OpPC, ThisPtr.view(), DynamicDecl)) return false; assert(DynamicDecl); @@ -2194,7 +2221,7 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, const auto *InitialFunction = cast<CXXMethodDecl>(Callee); const CXXMethodDecl *Overrider; - if (StaticDecl != DynamicDecl && !S.initializingBlock(ThisPtr.block())) { + if (StaticDecl != DynamicDecl) { if (!DynamicDecl->isDerivedFrom(StaticDecl)) return false; Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl, diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h index 8a413d01d2dd5..dda5ac61ef126 100644 --- a/clang/lib/AST/ByteCode/Pointer.h +++ b/clang/lib/AST/ByteCode/Pointer.h @@ -61,6 +61,10 @@ struct PtrView { return Base == Pointee->getDescriptor()->getMetadataSize(); } + bool isConst() const { + return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; + } + InlineDescriptor *getInlineDesc() const { assert(Base != sizeof(GlobalInlineDescriptor)); assert(Base <= Pointee->getSize()); @@ -137,6 +141,13 @@ struct PtrView { return PtrView{Pointee, Next, Offset}; } + [[nodiscard]] PtrView stripBaseCasts() const { + PtrView V = *this; + while (V.isBaseClass()) + V = V.getBase(); + return V; + } + [[nodiscard]] PtrView getArray() const { assert(Offset != Base && "not an array element"); return PtrView{Pointee, Base, Base}; @@ -758,7 +769,7 @@ class Pointer { bool isConst() const { if (isIntegralPointer()) return true; - return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; + return view().isConst(); } bool isConstInMutable() const { if (!isBlockPointer()) @@ -985,10 +996,7 @@ class Pointer { /// The result is either a root pointer or something /// that isn't a base class anymore. [[nodiscard]] Pointer stripBaseCasts() const { - PtrView V = view(); - while (V.isBaseClass()) - V = V.getBase(); - return Pointer(V); + return Pointer(view().stripBaseCasts()); } /// Compare two pointers. diff --git a/clang/test/AST/ByteCode/cxx20.cpp b/clang/test/AST/ByteCode/cxx20.cpp index b7ca154a0a987..70ff1045a74da 100644 --- a/clang/test/AST/ByteCode/cxx20.cpp +++ b/clang/test/AST/ByteCode/cxx20.cpp @@ -1099,8 +1099,7 @@ namespace Virtual { static_assert(d.b == 'B'); static_assert(d.c == 'C'); // During the construction of C, the dynamic type of B's A is B. - static_assert(d.ba == 'B'); // expected-error {{failed}} \ - // expected-note {{expression evaluates to}} + static_assert(d.ba == 'B'); static_assert(d.d == 'D'); static_assert(d.f() == 'D'); constexpr const A &a = (B&)d; diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp index 78769a4def5b0..03c41edf7a70a 100644 --- a/clang/test/AST/ByteCode/cxx2a.cpp +++ b/clang/test/AST/ByteCode/cxx2a.cpp @@ -54,6 +54,39 @@ namespace Covariant { static_assert(cb1->f()->a == 'Z'); } +namespace Covariant2 { + struct A { + }; + struct B : A { + }; + struct C : A { + }; + struct D : B, C { + }; + + // Check that we apply a proper adjustment for a covariant return type. + struct Covariant1 { + D d; + virtual const A *f() const; + }; + + template<typename T> + struct Covariant2 : Covariant1 { + virtual const T *f() const; + }; + + template<typename T> + struct Covariant3 : Covariant2<T> { + constexpr virtual const D *f() const { return &this->d; } + }; + + constexpr Covariant3<C> cc; + constexpr const Covariant1 *cc1 = &cc; + + // LHS static type is A*. + static_assert(cc1->f() == (C*)&cc.d); // expected-error {{static assertion failed}} +} + namespace DtorOrder { struct Buf { char buf[64]; diff --git a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.general/p16-cxx20.cpp b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.general/p16-cxx20.cpp index fc6908fefac85..0d49a93af86cc 100644 --- a/clang/test/CXX/dcl.decl/dcl.init/dcl.init.general/p16-cxx20.cpp +++ b/clang/test/CXX/dcl.decl/dcl.init/dcl.init.general/p16-cxx20.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++20 %s -fexperimental-new-constant-interpreter namespace GH69890 { // If the initializer is (), the object is value-initialized. `````````` </details> https://github.com/llvm/llvm-project/pull/207722 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
