Skip to content
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
32 changes: 15 additions & 17 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1644,8 +1644,8 @@ static bool GetDynamicDecl(InterpState &S, CodePtr OpPC, Pointer TypePtr,

QualType DynamicType = TypePtr.getType();
if (TypePtr.isStatic() || TypePtr.isConst()) {
const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
if (!VD->isConstexpr()) {
if (const VarDecl *VD = TypePtr.getDeclDesc()->asVarDecl();
VD && !VD->isConstexpr()) {
const Expr *E = S.Current->getExpr(OpPC);
APValue V = TypePtr.toAPValue(S.getASTContext());
QualType TT = S.getASTContext().getLValueReferenceType(DynamicType);
Expand Down Expand Up @@ -1676,20 +1676,6 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
const FunctionDecl *Callee = Func->getDecl();

if (!Func->isFullyCompiled())
compileFunction(S, Func);

// C++2a [class.abstract]p6:
// the effect of making a virtual call to a pure virtual function [...] is
// undefined
if (Callee->isPureVirtual()) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1)
<< Callee;
S.Note(Callee->getLocation(), diag::note_declared_at);
return false;
}

const CXXRecordDecl *DynamicDecl = nullptr;
if (!GetDynamicDecl(S, OpPC, ThisPtr, DynamicDecl))
return false;
Expand All @@ -1699,7 +1685,8 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
const CXXMethodDecl *Overrider;

if (StaticDecl != DynamicDecl) {
if (StaticDecl != DynamicDecl &&
!llvm::is_contained(S.InitializingBlocks, ThisPtr.block())) {
if (!DynamicDecl->isDerivedFrom(StaticDecl))
return false;
Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
Expand All @@ -1709,6 +1696,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
Overrider = InitialFunction;
}

// C++2a [class.abstract]p6:
// the effect of making a virtual call to a pure virtual function [...] is
// undefined
if (Overrider->isPureVirtual()) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1)
<< Callee;
S.Note(Callee->getLocation(), diag::note_declared_at);
return false;
}

if (Overrider != InitialFunction) {
// DR1872: An instantiated virtual constexpr function can't be called in a
// constant expression (prior to C++20). We can still constant-fold such a
Expand Down
18 changes: 18 additions & 0 deletions clang/test/AST/ByteCode/cxx20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1183,3 +1183,21 @@ namespace VirtualFunctionCallThroughArrayElem {
static_assert(a[2][3].foo()); // both-error {{not an integral constant expression}} \
// both-note {{virtual function called on object 'a[2][3]' whose dynamic type is not constant}}
}

namespace NonPureVirtualCall {
struct A {
constexpr virtual void call(int) = 0;
constexpr void call2() { call(0); }
};

struct B : A {
constexpr void call(int) override {}
};

consteval void check() {
B b;
b.call2();
}

int main() { check(); }
}