Skip to content

Commit f78d288

Browse files
authored
[clang][Interp] Fix function pointer callexpr eval order (#101821)
We need to evaluate the callee before the arguments.
1 parent 2bae7ae commit f78d288

File tree

2 files changed

+15
-12
lines changed

2 files changed

+15
-12
lines changed

clang/lib/AST/Interp/Compiler.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4003,6 +4003,13 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
40034003
} else if (!this->visit(MC->getImplicitObjectArgument())) {
40044004
return false;
40054005
}
4006+
} else if (!FuncDecl) {
4007+
const Expr *Callee = E->getCallee();
4008+
CalleeOffset = this->allocateLocalPrimitive(Callee, PT_FnPtr, true, false);
4009+
if (!this->visit(Callee))
4010+
return false;
4011+
if (!this->emitSetLocal(PT_FnPtr, *CalleeOffset, E))
4012+
return false;
40064013
}
40074014

40084015
llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args);
@@ -4071,22 +4078,19 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
40714078
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
40724079
ArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));
40734080

4074-
// Get the callee, either from a member pointer saved in CalleeOffset,
4075-
// or by just visiting the Callee expr.
4076-
if (CalleeOffset) {
4081+
// Get the callee, either from a member pointer or function pointer saved in
4082+
// CalleeOffset.
4083+
if (isa<CXXMemberCallExpr>(E) && CalleeOffset) {
40774084
if (!this->emitGetLocal(PT_MemberPtr, *CalleeOffset, E))
40784085
return false;
40794086
if (!this->emitGetMemberPtrDecl(E))
40804087
return false;
4081-
if (!this->emitCallPtr(ArgSize, E, E))
4082-
return false;
40834088
} else {
4084-
if (!this->visit(E->getCallee()))
4085-
return false;
4086-
4087-
if (!this->emitCallPtr(ArgSize, E, E))
4089+
if (!this->emitGetLocal(PT_FnPtr, *CalleeOffset, E))
40884090
return false;
40894091
}
4092+
if (!this->emitCallPtr(ArgSize, E, E))
4093+
return false;
40904094
}
40914095

40924096
// Cleanup for discarded return values.

clang/test/AST/Interp/eval-order.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ namespace EvalOrder {
4545
}
4646
template <typename T> constexpr T &&b(T &&v) {
4747
if (!done_a)
48-
throw "wrong"; // expected-note 5{{not valid}}
48+
throw "wrong"; // expected-note 4{{not valid}}
4949
done_b = true;
5050
return (T &&)v;
5151
}
@@ -75,8 +75,7 @@ namespace EvalOrder {
7575
SEQ(A(&ud)->*B(&UserDefined::n));
7676

7777
// Rule 4: a(b1, b2, b3)
78-
SEQ(A(f)(B(1), B(2), B(3))); // expected-error {{not an integral constant expression}} FIXME \
79-
// expected-note 2{{in call to}}
78+
SEQ(A(f)(B(1), B(2), B(3)));
8079

8180
// Rule 5: b = a, b @= a
8281
SEQ(B(lvalue<int>().get()) = A(0)); // expected-error {{not an integral constant expression}} FIXME \

0 commit comments

Comments
 (0)