From 35b6d1f0b4ac154ee41c704b0d0f575fc3e81626 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Wed, 25 Sep 2024 18:13:48 +0200 Subject: [PATCH 1/7] DFuncValue: Add explicit funcPtr field As preparation for using a LL pair as rvalue if the expression type is Tdelegate. --- gen/dvalue.cpp | 11 ++++++----- gen/dvalue.h | 11 ++++++----- gen/llvmhelpers.cpp | 2 +- gen/toir.cpp | 15 +++++++-------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index bdad72263b0..9c822c21984 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -105,13 +105,14 @@ LLValue *DSliceValue::getPtr() { //////////////////////////////////////////////////////////////////////////////// -DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *v, LLValue *vt, - LLValue *vtable) - : DRValue(t, v), func(fd), vthis(vt), vtable(vtable) {} +DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *funcPtr, + LLValue *vt, LLValue *vtable) + : DRValue(t, funcPtr), func(fd), funcPtr(funcPtr), vthis(vt), + vtable(vtable) {} -DFuncValue::DFuncValue(FuncDeclaration *fd, LLValue *v, LLValue *vt, +DFuncValue::DFuncValue(FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, LLValue *vtable) - : DFuncValue(fd->type, fd, v, vt, vtable) {} + : DFuncValue(fd->type, fd, funcPtr, vt, vtable) {} bool DFuncValue::definedInFuncEntryBB() { return isDefinedInFuncEntryBB(val) && diff --git a/gen/dvalue.h b/gen/dvalue.h index 3a1b779d93c..fd22e4457e0 100644 --- a/gen/dvalue.h +++ b/gen/dvalue.h @@ -141,14 +141,15 @@ class DSliceValue : public DRValue { /// optional vtable pointer. class DFuncValue : public DRValue { public: - FuncDeclaration *func; - llvm::Value *vthis; + FuncDeclaration *const func; + llvm::Value *const funcPtr; + llvm::Value *const vthis; llvm::Value *vtable; - DFuncValue(Type *t, FuncDeclaration *fd, llvm::Value *v, + DFuncValue(Type *t, FuncDeclaration *fd, llvm::Value *funcPtr, + llvm::Value *vt = nullptr, llvm::Value *vtable = nullptr); + DFuncValue(FuncDeclaration *fd, llvm::Value *funcPtr, llvm::Value *vt = nullptr, llvm::Value *vtable = nullptr); - DFuncValue(FuncDeclaration *fd, llvm::Value *v, llvm::Value *vt = nullptr, - llvm::Value *vtable = nullptr); bool definedInFuncEntryBB() override; diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 0cc63e70b8f..ad808626d50 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -767,7 +767,7 @@ DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to) { } } else if (auto func = val->isFunc()) { if (tb->ty == TY::Tdelegate) { - return new DFuncValue(to, func->func, DtoRVal(func), func->vthis); + return new DFuncValue(to, func->func, func->funcPtr, func->vthis); } } else { // generic rvalue LLValue *rval = DtoRVal(val); diff --git a/gen/toir.cpp b/gen/toir.cpp index be09d2a682b..a9bce8856ec 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -984,11 +984,10 @@ class ToElemVisitor : public Visitor { // function pointers are special if (e->type->toBasetype()->ty == TY::Tfunction) { DValue *dv = toElem(e->e1); - LLValue *llVal = DtoRVal(dv); if (DFuncValue *dfv = dv->isFunc()) { - result = new DFuncValue(e->type, dfv->func, llVal); + result = new DFuncValue(e->type, dfv->func, dfv->funcPtr); } else { - result = new DImValue(e->type, llVal); + result = new DImValue(e->type, DtoRVal(dv)); } return; } @@ -1072,18 +1071,18 @@ class ToElemVisitor : public Visitor { fdecl->visibility.kind != Visibility::package_; // Get the actual function value to call. - LLValue *funcval = nullptr; + LLValue *funcPtr = nullptr; LLValue *vtable = nullptr; if (nonFinal) { DtoResolveFunction(fdecl); - std::tie(funcval, vtable) = DtoVirtualFunctionPointer(l, fdecl); + std::tie(funcPtr, vtable) = DtoVirtualFunctionPointer(l, fdecl); } else { - funcval = DtoCallee(fdecl); + funcPtr = DtoCallee(fdecl); } - assert(funcval); + assert(funcPtr); LLValue *vthis = (DtoIsInMemoryOnly(l->type) ? DtoLVal(l) : DtoRVal(l)); - result = new DFuncValue(fdecl, funcval, vthis, vtable); + result = new DFuncValue(fdecl, funcPtr, vthis, vtable); } else { llvm_unreachable("Unknown target for VarDeclaration."); } From cd03f5474542f73ce23e3d9a92980d1cf3236633 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Wed, 25 Sep 2024 19:22:22 +0200 Subject: [PATCH 2/7] [step 2] --- gen/toir.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gen/toir.cpp b/gen/toir.cpp index a9bce8856ec..bc72a5bfc92 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -947,7 +947,8 @@ class ToElemVisitor : public Visitor { // Logger::println("FuncDeclaration"); FuncDeclaration *fd = fv->func; assert(fd); - result = new DFuncValue(fd, DtoCallee(fd)); + result = + fv->type == e->type ? fv : new DFuncValue(e->type, fd, fv->funcPtr); return; } if (v->isIm()) { @@ -985,8 +986,11 @@ class ToElemVisitor : public Visitor { if (e->type->toBasetype()->ty == TY::Tfunction) { DValue *dv = toElem(e->e1); if (DFuncValue *dfv = dv->isFunc()) { - result = new DFuncValue(e->type, dfv->func, dfv->funcPtr); + result = dfv->type == e->type + ? dfv + : new DFuncValue(e->type, dfv->func, dfv->funcPtr); } else { + // FIXME: should not reach this result = new DImValue(e->type, DtoRVal(dv)); } return; @@ -1952,6 +1956,7 @@ class ToElemVisitor : public Visitor { LLValue *contextptr; if (DFuncValue *f = u->isFunc()) { assert(f->func); + // FIXME: use f->vthis contextptr = DtoNestedContext(e->loc, f->func); } else { contextptr = (DtoIsInMemoryOnly(u->type) ? DtoLVal(u) : DtoRVal(u)); @@ -1988,6 +1993,7 @@ class ToElemVisitor : public Visitor { fptr = DtoCallee(e->func); } + // FIXME: use DFuncValue result = new DImValue( e->type, DtoAggrPair(DtoType(e->type), contextptr, fptr, ".dg")); } @@ -2280,8 +2286,9 @@ class ToElemVisitor : public Visitor { genFuncLiteral(fd, e); LLFunction *callee = DtoCallee(fd, false); - if (fd->isNested()) { + if (fd->isNested()) { // FIXME: if e->type->toBasetype() is a Tdelegate? LLValue *cval = DtoNestedContext(e->loc, fd); + // FIXME: use DFuncValue result = new DImValue(e->type, DtoAggrPair(cval, callee, ".func")); } else { result = new DFuncValue(e->type, fd, callee); From df190796af5fba5e390042a905d27c1481986de8 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Wed, 25 Sep 2024 20:19:55 +0200 Subject: [PATCH 3/7] [add assertions for DFuncValue types] --- gen/dvalue.cpp | 7 ++++++- gen/llvmhelpers.cpp | 4 ++-- gen/toir.cpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index 9c822c21984..fb6d6191e72 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -108,7 +108,12 @@ LLValue *DSliceValue::getPtr() { DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, LLValue *vtable) : DRValue(t, funcPtr), func(fd), funcPtr(funcPtr), vthis(vt), - vtable(vtable) {} + vtable(vtable) { + const auto tb = t->toBasetype(); + assert(tb->ty == TY::Tfunction || tb->ty == TY::Tdelegate || + (tb->ty == TY::Tpointer && + tb->nextOf()->toBasetype()->ty == TY::Tfunction)); +} DFuncValue::DFuncValue(FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, LLValue *vtable) diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index ad808626d50..37fa1594cb6 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1538,7 +1538,7 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) { // to the module member list. DtoDefineFunction(flitdecl); - return new DFuncValue(flitdecl, DtoCallee(flitdecl, false)); + return new DFuncValue(type, flitdecl, DtoCallee(flitdecl, false)); } if (FuncDeclaration *fdecl = decl->isFuncDeclaration()) { @@ -1555,7 +1555,7 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) { } DtoResolveFunction(fdecl); assert(!DtoIsMagicIntrinsic(fdecl)); - return new DFuncValue(fdecl, DtoCallee(fdecl)); + return new DFuncValue(type, fdecl, DtoCallee(fdecl)); } if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) { diff --git a/gen/toir.cpp b/gen/toir.cpp index bc72a5bfc92..81ac56da7aa 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1086,7 +1086,7 @@ class ToElemVisitor : public Visitor { assert(funcPtr); LLValue *vthis = (DtoIsInMemoryOnly(l->type) ? DtoLVal(l) : DtoRVal(l)); - result = new DFuncValue(fdecl, funcPtr, vthis, vtable); + result = new DFuncValue(e->type, fdecl, funcPtr, vthis, vtable); } else { llvm_unreachable("Unknown target for VarDeclaration."); } From 6b7c533b45726782dcbb3d83197f32c568479427 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Thu, 26 Sep 2024 10:37:55 +0200 Subject: [PATCH 4/7] DFuncValue: Store LL pair as rvalue for delegates --- gen/dvalue.cpp | 16 ++++++++++++++-- gen/toir.cpp | 30 ++++++++++++++++-------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index fb6d6191e72..29dd3cfa16b 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -105,11 +105,23 @@ LLValue *DSliceValue::getPtr() { //////////////////////////////////////////////////////////////////////////////// +namespace { +LLValue *createFuncRValue(Type *t, LLValue *funcPtr, LLValue *vthis) { + if (t->toBasetype()->ty == TY::Tdelegate) { + assert(vthis); + return DtoAggrPair(vthis, funcPtr); + } + return funcPtr; +} +} + DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, LLValue *vtable) - : DRValue(t, funcPtr), func(fd), funcPtr(funcPtr), vthis(vt), - vtable(vtable) { + : DRValue(t, createFuncRValue(t, funcPtr, vt)), func(fd), funcPtr(funcPtr), + vthis(vt), vtable(vtable) { +#ifndef NDEBUG const auto tb = t->toBasetype(); +#endif assert(tb->ty == TY::Tfunction || tb->ty == TY::Tdelegate || (tb->ty == TY::Tpointer && tb->nextOf()->toBasetype()->ty == TY::Tfunction)); diff --git a/gen/toir.cpp b/gen/toir.cpp index 81ac56da7aa..90edcf52dab 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -947,8 +947,9 @@ class ToElemVisitor : public Visitor { // Logger::println("FuncDeclaration"); FuncDeclaration *fd = fv->func; assert(fd); - result = - fv->type == e->type ? fv : new DFuncValue(e->type, fd, fv->funcPtr); + result = fv->type == e->type + ? fv + : new DFuncValue(e->type, fd, fv->funcPtr, fv->vthis); return; } if (v->isIm()) { @@ -986,9 +987,10 @@ class ToElemVisitor : public Visitor { if (e->type->toBasetype()->ty == TY::Tfunction) { DValue *dv = toElem(e->e1); if (DFuncValue *dfv = dv->isFunc()) { - result = dfv->type == e->type - ? dfv - : new DFuncValue(e->type, dfv->func, dfv->funcPtr); + result = + dfv->type == e->type + ? dfv + : new DFuncValue(e->type, dfv->func, dfv->funcPtr, dfv->vthis); } else { // FIXME: should not reach this result = new DImValue(e->type, DtoRVal(dv)); @@ -1955,9 +1957,11 @@ class ToElemVisitor : public Visitor { DValue *u = toElem(e->e1); LLValue *contextptr; if (DFuncValue *f = u->isFunc()) { - assert(f->func); - // FIXME: use f->vthis - contextptr = DtoNestedContext(e->loc, f->func); + contextptr = f->vthis; + if (!contextptr) { + assert(f->func); + contextptr = DtoNestedContext(e->loc, f->func); + } } else { contextptr = (DtoIsInMemoryOnly(u->type) ? DtoLVal(u) : DtoRVal(u)); } @@ -1993,9 +1997,7 @@ class ToElemVisitor : public Visitor { fptr = DtoCallee(e->func); } - // FIXME: use DFuncValue - result = new DImValue( - e->type, DtoAggrPair(DtoType(e->type), contextptr, fptr, ".dg")); + result = new DFuncValue(e->type, e->func, fptr, contextptr); } ////////////////////////////////////////////////////////////////////////////// @@ -2286,11 +2288,11 @@ class ToElemVisitor : public Visitor { genFuncLiteral(fd, e); LLFunction *callee = DtoCallee(fd, false); - if (fd->isNested()) { // FIXME: if e->type->toBasetype() is a Tdelegate? + if (e->type->toBasetype()->ty == TY::Tdelegate) { LLValue *cval = DtoNestedContext(e->loc, fd); - // FIXME: use DFuncValue - result = new DImValue(e->type, DtoAggrPair(cval, callee, ".func")); + result = new DFuncValue(e->type, fd, callee, cval); } else { + assert(!fd->isNested()); result = new DFuncValue(e->type, fd, callee); } } From 9880a3f51b585fce2d2e9c730fdc4a112d062b52 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sat, 28 Sep 2024 14:50:54 +0200 Subject: [PATCH 5/7] [next step: ensure no more DImValues for function ptrs and delegates] --- gen/dvalue.cpp | 32 ++++++++++++++++++-------------- gen/llvmhelpers.cpp | 13 +++++++++---- gen/tocall.cpp | 18 +++++++++++++----- gen/toir.cpp | 27 ++++++++++++++++++++++----- 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index 29dd3cfa16b..86d3b935809 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -64,13 +64,16 @@ DRValue::DRValue(Type *t, LLValue *v) : DValue(t, v) { //////////////////////////////////////////////////////////////////////////////// DImValue::DImValue(Type *t, llvm::Value *v) : DRValue(t, v) { - // TODO: get rid of Tfunction exception +#ifndef NDEBUG + const auto tb = t->toBasetype(); +#endif + assert(tb->ty != TY::Tarray && "use DSliceValue for dynamic arrays"); + assert(!tb->isFunction_Delegate_PtrToFunction() && + "use DFuncValue for function pointers and delegates"); + // v may be an addrspace qualified pointer so strip it before doing a pointer // equality check. - assert(t->toBasetype()->ty == TY::Tfunction || - stripAddrSpaces(v->getType()) == DtoType(t)); - assert(t->toBasetype()->ty != TY::Tarray && - "use DSliceValue for dynamic arrays"); + assert(stripAddrSpaces(v->getType()) == DtoType(t)); } //////////////////////////////////////////////////////////////////////////////// @@ -119,12 +122,7 @@ DFuncValue::DFuncValue(Type *t, FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, LLValue *vtable) : DRValue(t, createFuncRValue(t, funcPtr, vt)), func(fd), funcPtr(funcPtr), vthis(vt), vtable(vtable) { -#ifndef NDEBUG - const auto tb = t->toBasetype(); -#endif - assert(tb->ty == TY::Tfunction || tb->ty == TY::Tdelegate || - (tb->ty == TY::Tpointer && - tb->nextOf()->toBasetype()->ty == TY::Tfunction)); + assert(t->toBasetype()->isFunction_Delegate_PtrToFunction()); } DFuncValue::DFuncValue(FuncDeclaration *fd, LLValue *funcPtr, LLValue *vt, @@ -150,8 +148,8 @@ DRValue *DLValue::getRVal() { LLValue *rval = DtoLoad(DtoMemType(type), val); - const auto ty = type->toBasetype()->ty; - if (ty == TY::Tbool) { + const auto tb = type->toBasetype(); + if (tb->ty == TY::Tbool) { assert(rval->getType() == llvm::Type::getInt8Ty(gIR->context())); if (isOptimizationEnabled()) { @@ -164,8 +162,14 @@ DRValue *DLValue::getRVal() { // truncate to i1 rval = gIR->ir->CreateTrunc(rval, llvm::Type::getInt1Ty(gIR->context())); - } else if (ty == TY::Tarray) { + } else if (tb->ty == TY::Tarray) { return new DSliceValue(type, rval); + } else if (tb->isPtrToFunction()) { + return new DFuncValue(type, nullptr, rval); + } else if (tb->ty == TY::Tdelegate) { + const auto contextPtr = DtoExtractValue(rval, 0, ".ptr"); + const auto funcPtr = DtoExtractValue(rval, 1, ".funcptr"); + return new DFuncValue(type, nullptr, funcPtr, contextPtr); } return new DImValue(type, rval); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 37fa1594cb6..910e16eb7be 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -527,6 +527,10 @@ DValue *DtoCastInt(const Loc &loc, DValue *val, Type *_to) { } else { rval = new llvm::SIToFPInst(rval, tolltype, "", gIR->scopebb()); } + } else if (to->isPtrToFunction()) { + IF_LOG Logger::cout() << "cast function pointer: " << *tolltype << '\n'; + rval = gIR->ir->CreateIntToPtr(rval, tolltype); + return new DFuncValue(_to, nullptr, rval); } else if (to->ty == TY::Tpointer) { IF_LOG Logger::cout() << "cast pointer: " << *tolltype << '\n'; rval = gIR->ir->CreateIntToPtr(rval, tolltype); @@ -569,7 +573,9 @@ DValue *DtoCastPtr(const Loc &loc, DValue *val, Type *to) { fatal(); } - return new DImValue(to, rval); + return totype->isPtrToFunction() + ? static_cast(new DFuncValue(to, nullptr, rval)) + : static_cast(new DImValue(to, rval)); } DValue *DtoCastFloat(const Loc &loc, DValue *val, Type *to) { @@ -766,9 +772,8 @@ DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to) { return new DSliceValue(to, slice->getLength(), slice->getPtr()); } } else if (auto func = val->isFunc()) { - if (tb->ty == TY::Tdelegate) { - return new DFuncValue(to, func->func, func->funcPtr, func->vthis); - } + return new DFuncValue(to, func->func, func->funcPtr, + tb->ty == TY::Tdelegate ? func->vthis : nullptr); } else { // generic rvalue LLValue *rval = DtoRVal(val); LLType *tll = DtoType(tb); diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 97f5ca9f0cd..681245957cd 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -712,8 +712,9 @@ class ImplicitArgumentsBuilder { size_t index = args.size(); - if (dfnval && (dfnval->func->ident == Id::ensure || - dfnval->func->ident == Id::require)) { + if (dfnval && dfnval->func && + (dfnval->func->ident == Id::ensure || + dfnval->func->ident == Id::require)) { // can be the this "context" argument for a contract invocation // (pass a pointer to the aggregate `this` pointer, which can naturally be // used as the contract's parent context in case the contract features @@ -747,7 +748,7 @@ class ImplicitArgumentsBuilder { args.push_back(ctxarg); } else if (nestedcall) { // ... or a nested function context arg - if (dfnval) { + if (dfnval && dfnval->func) { LLValue *contextptr = DtoNestedContext(loc, dfnval->func); args.push_back(contextptr); } else { @@ -767,6 +768,7 @@ class ImplicitArgumentsBuilder { if (irFty.arg_objcSelector) { assert(dfnval); + assert(dfnval->func); const auto selector = dfnval->func->objc.selector; assert(selector); LLGlobalVariable *selptr = gIR->objc.getMethVarRef(*selector); @@ -836,7 +838,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval, // get callee llvm value LLValue *callable = DtoCallableValue(fnval); LLFunctionType *callableTy = irFty.funcType; - if (dfnval && dfnval->func->isCsymbol()) { + if (dfnval && dfnval->func && dfnval->func->isCsymbol()) { // See note in DtoDeclareFunction about K&R foward declared (void) functions // later defined as (...) functions. We want to use the non-variadic one. if (irFty.funcType->getNumParams() == 0 && irFty.funcType->isVarArg()) @@ -1017,7 +1019,7 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval, attrlist = llvm::Intrinsic::getAttributes(gIR->context(), cf->getIntrinsicID()); } - } else if (dfnval) { + } else if (dfnval && dfnval->func) { call->setCallingConv(getCallingConvention(dfnval->func)); } else { call->setCallingConv(gABI->callingConv(tf, iab.hasContext)); @@ -1044,6 +1046,12 @@ DValue *DtoCallFunction(const Loc &loc, Type *resulttype, DValue *fnval, if (rbase->ty == TY::Tarray) { return new DSliceValue(resulttype, retllval); + } else if (rbase->isPtrToFunction()) { + return new DFuncValue(resulttype, nullptr, retllval); + } else if (rbase->ty == TY::Tdelegate) { + const auto contextPtr = DtoExtractValue(retllval, 0, ".ptr"); + const auto funcPtr = DtoExtractValue(retllval, 1, ".funcptr"); + return new DFuncValue(resulttype, nullptr, funcPtr, contextPtr); } return new DImValue(resulttype, retllval); diff --git a/gen/toir.cpp b/gen/toir.cpp index 90edcf52dab..d6cb5784c36 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -880,8 +880,20 @@ class ToElemVisitor : public Visitor { llvm::Value *offsetValue = nullptr; + const auto tb = e->type->toBasetype(); + assert(tb->ty != TY::Tdelegate); + assert(tb->ty != TY::Tfunction); + if (e->offset == 0) { offsetValue = baseValue; + + if (tb->isPtrToFunction()) + if (auto dfn = base->isFunc()) { + result = e->type == dfn->type + ? dfn + : new DFuncValue(e->type, dfn->func, dfn->funcPtr); + return; + } } else { LLType *elemType = DtoType(base->type); if (elemType->isSized()) { @@ -912,9 +924,14 @@ class ToElemVisitor : public Visitor { } } + if (tb->isPtrToFunction()) { + result = new DFuncValue(e->type, nullptr, offsetValue); + return; + } + // Casts are also "optimized into" SymOffExp by the frontend. - LLValue *llVal = (e->type->toBasetype()->isintegral() - ? p->ir->CreatePtrToInt(offsetValue, DtoType(e->type)) + LLValue *llVal = + (tb->isintegral() ? p->ir->CreatePtrToInt(offsetValue, DtoType(e->type)) : DtoBitCast(offsetValue, DtoType(e->type))); result = new DImValue(e->type, llVal); } @@ -993,7 +1010,7 @@ class ToElemVisitor : public Visitor { : new DFuncValue(e->type, dfv->func, dfv->funcPtr, dfv->vthis); } else { // FIXME: should not reach this - result = new DImValue(e->type, DtoRVal(dv)); + result = new DFuncValue(e->type, nullptr, DtoRVal(dv)); } return; } @@ -2928,8 +2945,8 @@ bool toInPlaceConstruction(DLValue *lhs, Expression *rhs) { Logger::println("is a constructor call, checking lhs of DotVarExp"); if (toInPlaceConstruction(lhs, dve->e1)) { Logger::println("success, calling ctor on in-place constructed lhs"); - auto fnval = new DFuncValue(fd, DtoCallee(fd), DtoLVal(lhs)); - DtoCallFunction(ce->loc, ce->type, fnval, ce->arguments); + auto fnval = DFuncValue(fd, DtoCallee(fd), DtoLVal(lhs)); + DtoCallFunction(ce->loc, ce->type, &fnval, ce->arguments); return true; } } From 9a2264b9baa3096f47b9b9294e754916a36ce4ba Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Tue, 1 Oct 2024 19:49:37 +0200 Subject: [PATCH 6/7] Add testcase for issue #4759 --- tests/compilable/gh4759.d | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compilable/gh4759.d diff --git a/tests/compilable/gh4759.d b/tests/compilable/gh4759.d new file mode 100644 index 00000000000..443ce4dcc0a --- /dev/null +++ b/tests/compilable/gh4759.d @@ -0,0 +1,7 @@ +// RUN: %ldc -c %s + +void func(void delegate()) +{ + enum ident(alias F) = __traits(identifier, __traits(parent, F)); + func({ enum i = ident!({}); }); +} From 4e5e3668b900b9eb64586d92fdba40c33e0658b9 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Sun, 6 Oct 2024 19:24:29 +0200 Subject: [PATCH 7/7] [add DFuncValue::paintAs() method] --- gen/dvalue.cpp | 9 +++++++++ gen/dvalue.h | 2 ++ gen/llvmhelpers.cpp | 3 +-- gen/toir.cpp | 24 ++++++++---------------- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/gen/dvalue.cpp b/gen/dvalue.cpp index 86d3b935809..9650c4514ed 100644 --- a/gen/dvalue.cpp +++ b/gen/dvalue.cpp @@ -134,6 +134,15 @@ bool DFuncValue::definedInFuncEntryBB() { (!vthis || isDefinedInFuncEntryBB(vthis)); } +DFuncValue *DFuncValue::paintAs(Type *t) { + if (t == type) + return this; + + return new DFuncValue( + t, func, funcPtr, + vthis && t->toBasetype()->ty == TY::Tdelegate ? vthis : nullptr, vtable); +} + //////////////////////////////////////////////////////////////////////////////// DLValue::DLValue(Type *t, LLValue *v) : DValue(t, v) { diff --git a/gen/dvalue.h b/gen/dvalue.h index fd22e4457e0..a0698227b69 100644 --- a/gen/dvalue.h +++ b/gen/dvalue.h @@ -154,6 +154,8 @@ class DFuncValue : public DRValue { bool definedInFuncEntryBB() override; DFuncValue *isFunc() override { return this; } + + DFuncValue *paintAs(Type *t); }; /// Represents a D value in memory via a low-level lvalue (pointer). diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 910e16eb7be..aa7c82b4c0c 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -772,8 +772,7 @@ DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to) { return new DSliceValue(to, slice->getLength(), slice->getPtr()); } } else if (auto func = val->isFunc()) { - return new DFuncValue(to, func->func, func->funcPtr, - tb->ty == TY::Tdelegate ? func->vthis : nullptr); + return func->paintAs(to); } else { // generic rvalue LLValue *rval = DtoRVal(val); LLType *tll = DtoType(tb); diff --git a/gen/toir.cpp b/gen/toir.cpp index d6cb5784c36..25960d04f88 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -889,9 +889,7 @@ class ToElemVisitor : public Visitor { if (tb->isPtrToFunction()) if (auto dfn = base->isFunc()) { - result = e->type == dfn->type - ? dfn - : new DFuncValue(e->type, dfn->func, dfn->funcPtr); + result = dfn->paintAs(e->type); return; } } else { @@ -962,11 +960,8 @@ class ToElemVisitor : public Visitor { if (DFuncValue *fv = v->isFunc()) { Logger::println("is func"); // Logger::println("FuncDeclaration"); - FuncDeclaration *fd = fv->func; - assert(fd); - result = fv->type == e->type - ? fv - : new DFuncValue(e->type, fd, fv->funcPtr, fv->vthis); + assert(fv->func); + result = fv->paintAs(e->type); return; } if (v->isIm()) { @@ -1004,12 +999,8 @@ class ToElemVisitor : public Visitor { if (e->type->toBasetype()->ty == TY::Tfunction) { DValue *dv = toElem(e->e1); if (DFuncValue *dfv = dv->isFunc()) { - result = - dfv->type == e->type - ? dfv - : new DFuncValue(e->type, dfv->func, dfv->funcPtr, dfv->vthis); + result = dfv->paintAs(e->type); } else { - // FIXME: should not reach this result = new DFuncValue(e->type, nullptr, DtoRVal(dv)); } return; @@ -2305,13 +2296,14 @@ class ToElemVisitor : public Visitor { genFuncLiteral(fd, e); LLFunction *callee = DtoCallee(fd, false); + LLValue *contextPointer = nullptr; if (e->type->toBasetype()->ty == TY::Tdelegate) { - LLValue *cval = DtoNestedContext(e->loc, fd); - result = new DFuncValue(e->type, fd, callee, cval); + contextPointer = DtoNestedContext(e->loc, fd); } else { assert(!fd->isNested()); - result = new DFuncValue(e->type, fd, callee); } + + result = new DFuncValue(e->type, fd, callee, contextPointer); } //////////////////////////////////////////////////////////////////////////////