Skip to content

[clang][bytecode] Refuse to contruct objects with virtual bases #110142

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,25 @@ bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
return false;
}

static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
const Pointer &ThisPtr) {
assert(Func->isConstructor());

const Descriptor *D = ThisPtr.getFieldDesc();

// FIXME: I think this case is not 100% correct. E.g. a pointer into a
// subobject of a composite array.
if (!D->ElemRecord)
return true;

if (D->ElemRecord->getNumVirtualBases() == 0)
return true;

S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)
<< Func->getParentDecl();
return false;
}

bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
Expand Down Expand Up @@ -1117,6 +1136,9 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
if (!CheckInvoke(S, OpPC, ThisPtr))
return cleanup();
}

if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))
return false;
}

if (!CheckCallable(S, OpPC, Func))
Expand Down
15 changes: 15 additions & 0 deletions clang/test/AST/ByteCode/cxx23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ namespace VirtualBases {
/// Calls the constructor of D.
D d;
}

#if __cplusplus >= 202302L
struct VBase {};
struct HasVBase : virtual VBase {}; // all23-note 1{{virtual base class declared here}}
struct Derived : HasVBase {
constexpr Derived() {} // all23-error {{constexpr constructor not allowed in struct with virtual base class}}
};
template<typename T> struct DerivedFromVBase : T {
constexpr DerivedFromVBase();
};
constexpr int f(DerivedFromVBase<HasVBase>) {}
template<typename T> constexpr DerivedFromVBase<T>::DerivedFromVBase() : T() {}
constexpr int nVBase = (DerivedFromVBase<HasVBase>(), 0); // all23-error {{constant expression}} \
// all23-note {{cannot construct object of type 'DerivedFromVBase<VirtualBases::HasVBase>' with virtual base class in a constant expression}}
#endif
}

namespace LabelGoto {
Expand Down
Loading