Skip to content

Commit 02f923f

Browse files
authored
[clang][bytecode] Classify function pointers as PT_Ptr (#135026)
The Pointer class already has the capability to be a function pointer, but we still classifed function pointers as PT_FnPtr/FunctionPointer. This means when converting from a Pointer to a FunctionPointer, we lost the information of what the original Pointer pointed to.
1 parent 5587932 commit 02f923f

File tree

10 files changed

+91
-40
lines changed

10 files changed

+91
-40
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
463463

464464
if (!this->visit(SubExpr))
465465
return false;
466+
if (CE->getType()->isFunctionPointerType())
467+
return true;
466468
if (FromT == PT_Ptr)
467469
return this->emitPtrPtrCast(SubExprTy->isVoidPointerType(), CE);
468470
return true;
@@ -4921,10 +4923,10 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
49214923
} else if (!FuncDecl) {
49224924
const Expr *Callee = E->getCallee();
49234925
CalleeOffset =
4924-
this->allocateLocalPrimitive(Callee, PT_FnPtr, /*IsConst=*/true);
4926+
this->allocateLocalPrimitive(Callee, PT_Ptr, /*IsConst=*/true);
49254927
if (!this->visit(Callee))
49264928
return false;
4927-
if (!this->emitSetLocal(PT_FnPtr, *CalleeOffset, E))
4929+
if (!this->emitSetLocal(PT_Ptr, *CalleeOffset, E))
49284930
return false;
49294931
}
49304932

@@ -5011,7 +5013,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
50115013
if (!this->emitGetMemberPtrDecl(E))
50125014
return false;
50135015
} else {
5014-
if (!this->emitGetLocal(PT_FnPtr, *CalleeOffset, E))
5016+
if (!this->emitGetLocal(PT_Ptr, *CalleeOffset, E))
50155017
return false;
50165018
}
50175019
if (!this->emitCallPtr(ArgSize, E, E))

clang/lib/AST/ByteCode/Context.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
189189

190190
if (T->isFunctionPointerType() || T->isFunctionReferenceType() ||
191191
T->isFunctionType() || T->isBlockPointerType())
192-
return PT_FnPtr;
192+
return PT_Ptr;
193193

194194
if (T->isPointerOrReferenceType() || T->isObjCObjectPointerType())
195195
return PT_Ptr;

clang/lib/AST/ByteCode/Context.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,8 @@ class Context final {
7878
/// Classifies an expression.
7979
std::optional<PrimType> classify(const Expr *E) const {
8080
assert(E);
81-
if (E->isGLValue()) {
82-
if (E->getType()->isFunctionType())
83-
return PT_FnPtr;
81+
if (E->isGLValue())
8482
return PT_Ptr;
85-
}
8683

8784
return classify(E->getType());
8885
}

clang/lib/AST/ByteCode/EvalEmitter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
169169

170170
const Pointer &Ptr = S.Stk.pop<Pointer>();
171171

172+
if (Ptr.isFunctionPointer()) {
173+
EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
174+
return true;
175+
}
176+
172177
if (!EvalResult.checkReturnValue(S, Ctx, Ptr, Info))
173178
return false;
174179
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,6 @@ static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) {
9090
assert(S.Stk.size() == StackSizeBefore);
9191
S.Stk.push<Integral<32, true>>(
9292
Integral<32, true>::from(CheckBCPResult(S, Ptr)));
93-
} else if (PT == PT_FnPtr) {
94-
S.Stk.discard<FunctionPointer>();
95-
S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));
9693
} else {
9794
// Pop the result from the stack and return success.
9895
TYPE_SWITCH(PT, S.Stk.pop<T>(););
@@ -318,6 +315,8 @@ bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
318315
return false;
319316
if (Ptr.isZero())
320317
return true;
318+
if (Ptr.isFunctionPointer())
319+
return false;
321320
if (Ptr.isIntegralPointer())
322321
return true;
323322
if (Ptr.isTypeidPointer())
@@ -1621,20 +1620,24 @@ bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func,
16211620

16221621
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
16231622
const CallExpr *CE) {
1624-
const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();
1623+
const Pointer &Ptr = S.Stk.pop<Pointer>();
16251624

1626-
const Function *F = FuncPtr.getFunction();
1627-
if (!F) {
1625+
if (Ptr.isZero()) {
16281626
const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
16291627
S.FFDiag(E, diag::note_constexpr_null_callee)
16301628
<< const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
16311629
return false;
16321630
}
16331631

1634-
if (!FuncPtr.isValid() || !F->getDecl())
1632+
if (!Ptr.isFunctionPointer())
16351633
return Invalid(S, OpPC);
16361634

1635+
const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();
1636+
const Function *F = FuncPtr.getFunction();
16371637
assert(F);
1638+
// Don't allow calling block pointers.
1639+
if (!F->getDecl())
1640+
return Invalid(S, OpPC);
16381641

16391642
// This happens when the call expression has been cast to
16401643
// something else, but we don't support that.
@@ -1774,6 +1777,8 @@ bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
17741777
const Pointer &Ptr, unsigned BitWidth) {
17751778
if (Ptr.isDummy())
17761779
return false;
1780+
if (Ptr.isFunctionPointer())
1781+
return true;
17771782

17781783
const SourceInfo &E = S.Current->getSource(OpPC);
17791784
S.CCEDiag(E, diag::note_constexpr_invalid_cast)

clang/lib/AST/ByteCode/Interp.h

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -979,20 +979,6 @@ bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
979979
return CmpHelper<T>(S, OpPC, Fn);
980980
}
981981

982-
/// Function pointers cannot be compared in an ordered way.
983-
template <>
984-
inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,
985-
CompareFn Fn) {
986-
const auto &RHS = S.Stk.pop<FunctionPointer>();
987-
const auto &LHS = S.Stk.pop<FunctionPointer>();
988-
989-
const SourceInfo &Loc = S.Current->getSource(OpPC);
990-
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
991-
<< LHS.toDiagnosticString(S.getASTContext())
992-
<< RHS.toDiagnosticString(S.getASTContext());
993-
return false;
994-
}
995-
996982
template <>
997983
inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,
998984
CompareFn Fn) {
@@ -1019,18 +1005,27 @@ inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
10191005
const Pointer &RHS = S.Stk.pop<Pointer>();
10201006
const Pointer &LHS = S.Stk.pop<Pointer>();
10211007

1008+
// Function pointers cannot be compared in an ordered way.
1009+
if (LHS.isFunctionPointer() || RHS.isFunctionPointer()) {
1010+
const SourceInfo &Loc = S.Current->getSource(OpPC);
1011+
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
1012+
<< LHS.toDiagnosticString(S.getASTContext())
1013+
<< RHS.toDiagnosticString(S.getASTContext());
1014+
return false;
1015+
}
1016+
10221017
if (!Pointer::hasSameBase(LHS, RHS)) {
10231018
const SourceInfo &Loc = S.Current->getSource(OpPC);
10241019
S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)
10251020
<< LHS.toDiagnosticString(S.getASTContext())
10261021
<< RHS.toDiagnosticString(S.getASTContext());
10271022
return false;
1028-
} else {
1029-
unsigned VL = LHS.getByteOffset();
1030-
unsigned VR = RHS.getByteOffset();
1031-
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1032-
return true;
10331023
}
1024+
1025+
unsigned VL = LHS.getByteOffset();
1026+
unsigned VR = RHS.getByteOffset();
1027+
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
1028+
return true;
10341029
}
10351030

10361031
static inline bool IsOpaqueConstantCall(const CallExpr *E) {
@@ -1069,6 +1064,12 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
10691064
return false;
10701065
}
10711066

1067+
if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {
1068+
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(LHS.getIntegerRepresentation(),
1069+
RHS.getIntegerRepresentation()))));
1070+
return true;
1071+
}
1072+
10721073
if (Pointer::hasSameBase(LHS, RHS)) {
10731074
if (LHS.inUnion() && RHS.inUnion()) {
10741075
// If the pointers point into a union, things are a little more
@@ -2787,7 +2788,7 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
27872788

27882789
inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
27892790
assert(Func);
2790-
S.Stk.push<FunctionPointer>(Func);
2791+
S.Stk.push<Pointer>(Func);
27912792
return true;
27922793
}
27932794

@@ -2822,7 +2823,7 @@ inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {
28222823
const auto *FD = cast<FunctionDecl>(MP.getDecl());
28232824
const auto *Func = S.getContext().getOrCreateFunction(FD);
28242825

2825-
S.Stk.push<FunctionPointer>(Func);
2826+
S.Stk.push<Pointer>(Func);
28262827
return true;
28272828
}
28282829

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,15 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
152152
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
153153
Path,
154154
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
155-
if (isFunctionPointer())
156-
return asFunctionPointer().toAPValue(ASTCtx);
155+
if (isFunctionPointer()) {
156+
const FunctionPointer &FP = asFunctionPointer();
157+
if (const FunctionDecl *FD = FP.getFunction()->getDecl())
158+
return APValue(FD, CharUnits::fromQuantity(FP.getOffset() + Offset), {},
159+
/*OnePastTheEnd=*/false, /*IsNull=*/false);
160+
return APValue(FP.getFunction()->getExpr(),
161+
CharUnits::fromQuantity(FP.getOffset() + Offset), {},
162+
/*OnePastTheEnd=*/false, /*IsNull=*/false);
163+
}
157164

158165
if (isTypeidPointer()) {
159166
TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
@@ -379,6 +386,9 @@ std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
379386
if (isIntegralPointer())
380387
return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
381388

389+
if (isFunctionPointer())
390+
return asFunctionPointer().toDiagnosticString(Ctx);
391+
382392
return toAPValue(Ctx).getAsString(Ctx, getType());
383393
}
384394

clang/lib/AST/ByteCode/Pointer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,8 @@ class Pointer {
525525
}
526526

527527
bool isWeak() const {
528+
if (isFunctionPointer())
529+
return asFunctionPointer().isWeak();
528530
if (!isBlockPointer())
529531
return false;
530532

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s
3+
4+
template<typename T>
5+
struct Wrapper {
6+
T *Val;
7+
8+
template<typename _Up>
9+
constexpr Wrapper(_Up&& __u) {
10+
T& __f = static_cast<_Up&&>(__u);
11+
Val = &__f;
12+
}
13+
constexpr T& get() const { return *Val; }
14+
};
15+
16+
void f(){}
17+
int main() {
18+
auto W = Wrapper<decltype(f)>(f);
19+
20+
if (&W.get() != &f)
21+
__builtin_abort();
22+
}
23+
24+
/// We used to convert do the pointer->fnptr conversion
25+
/// by doing an integer conversion in between, which caused the
26+
/// %0 line to be:
27+
/// store ptr inttoptr (i64 138574454870464 to ptr), ptr %__f, align 8
28+
// CHECK: @_ZN7WrapperIFvvEEC2IRS0_EEOT_
29+
// CHECK: %0 = load ptr, ptr %__u.addr

clang/unittests/AST/ByteCode/toAPValue.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ TEST(ToAPValue, FunctionPointers) {
135135

136136
{
137137
const Pointer &GP = getGlobalPtr("func");
138-
const FunctionPointer &FP = GP.deref<FunctionPointer>();
138+
const Pointer &FP = GP.deref<Pointer>();
139139
ASSERT_FALSE(FP.isZero());
140140
APValue A = FP.toAPValue(ASTCtx);
141141
ASSERT_TRUE(A.hasValue());
@@ -193,7 +193,7 @@ TEST(ToAPValue, FunctionPointersC) {
193193
const ValueDecl *D = getDecl("func");
194194
const Pointer &GP = getGlobalPtr("func");
195195
ASSERT_TRUE(GP.isLive());
196-
const FunctionPointer &FP = GP.deref<FunctionPointer>();
196+
const Pointer &FP = GP.deref<Pointer>();
197197
ASSERT_FALSE(FP.isZero());
198198
APValue A = FP.toAPValue(ASTCtx);
199199
ASSERT_TRUE(A.hasValue());

0 commit comments

Comments
 (0)