Skip to content

Commit 16b0c2a

Browse files
committed
[cxx-interop] fix a clang assertion when synthesizing instance to static member call for operator ()
A specific static operator () in MSVC's STL triggers this assertion in clang when buidling CxxStdlib: Assertion failed: isInstance() && "No 'this' for static methods!", file S:\SourceCache\llvm-project\clang\lib\AST\DeclCXX.cpp, line 2544 When the return statement is being constructed using clang sema in Swift's function synthesis code. This change avoids using member call expression for a call to static operator (), and instead performs a direct call, which closer matches what Clang's semas typechecker expects, and the default Clang's parsing behavior as well. This fixes the windows toolchain build with MSVC.
1 parent ec09fa7 commit 16b0c2a

File tree

3 files changed

+63
-29
lines changed

3 files changed

+63
-29
lines changed

lib/ClangImporter/SwiftDeclSynthesizer.cpp

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,8 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(
20112011
assert(!method->isStatic() ||
20122012
method->getNameInfo().getName().getCXXOverloadedOperator() ==
20132013
clang::OO_Call);
2014+
// instance to static `operator ()` call.
2015+
bool isInstanceToStatic = method->isStatic();
20142016
// When emitting symbolic decls, the method might not have a concrete
20152017
// record type as this type.
20162018
if (ImporterImpl.importSymbolicCXXDecls && !method->isStatic() &&
@@ -2120,32 +2122,6 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(
21202122
clangSema.DelayedDiagnostics.getCurrentPool()};
21212123
auto diagState = clangSema.DelayedDiagnostics.push(diagPool);
21222124

2123-
// Construct the method's body.
2124-
clang::Expr *thisExpr = new (clangCtx) clang::CXXThisExpr(
2125-
clang::SourceLocation(), newMethod->getThisType(), /*IsImplicit=*/false);
2126-
if (castThisToNonConstThis) {
2127-
auto baseClassPtr =
2128-
clangCtx.getPointerType(clangCtx.getRecordType(derivedClass));
2129-
clang::CastKind Kind;
2130-
clang::CXXCastPath Path;
2131-
clangSema.CheckPointerConversion(thisExpr, baseClassPtr, Kind, Path,
2132-
/*IgnoreBaseAccess=*/false,
2133-
/*Diagnose=*/true);
2134-
auto conv = clangSema.ImpCastExprToType(thisExpr, baseClassPtr, Kind,
2135-
clang::VK_PRValue, &Path);
2136-
if (!conv.isUsable())
2137-
return nullptr;
2138-
thisExpr = conv.get();
2139-
}
2140-
2141-
auto memberExpr = clangSema.BuildMemberExpr(
2142-
thisExpr, /*isArrow=*/true, clang::SourceLocation(),
2143-
clang::NestedNameSpecifierLoc(), clang::SourceLocation(),
2144-
const_cast<clang::CXXMethodDecl *>(method),
2145-
clang::DeclAccessPair::make(const_cast<clang::CXXMethodDecl *>(method),
2146-
clang::AS_public),
2147-
/*HadMultipleCandidates=*/false, method->getNameInfo(),
2148-
clangCtx.BoundMemberTy, clang::VK_PRValue, clang::OK_Ordinary);
21492125
llvm::SmallVector<clang::Expr *, 4> args;
21502126
for (size_t i = 0; i < newMethod->getNumParams(); ++i) {
21512127
auto *param = newMethod->getParamDecl(i);
@@ -2156,9 +2132,51 @@ clang::CXXMethodDecl *SwiftDeclSynthesizer::synthesizeCXXForwardingMethod(
21562132
clangCtx, param, false, type, clang::ExprValueKind::VK_LValue,
21572133
clang::SourceLocation()));
21582134
}
2159-
auto memberCall = clangSema.BuildCallToMemberFunction(
2160-
nullptr, memberExpr, clang::SourceLocation(), args,
2161-
clang::SourceLocation());
2135+
2136+
clang::ExprResult memberCall;
2137+
if (isInstanceToStatic) {
2138+
// Constuct a direct call to a static member instead of going
2139+
// through a member expression to avoid clang's semantic analysis failure
2140+
// when analysis the return on a member with non-existing `this`.
2141+
auto memberExpr = new (clangCtx) clang::DeclRefExpr(
2142+
clangCtx, const_cast<clang::CXXMethodDecl *>(method), false,
2143+
method->getType(), clang::ExprValueKind::VK_LValue,
2144+
clang::SourceLocation());
2145+
memberCall =
2146+
clangSema.BuildCallExpr(nullptr, memberExpr, clang::SourceLocation(),
2147+
args, clang::SourceLocation());
2148+
} else {
2149+
// Construct the method's body.
2150+
clang::Expr *thisExpr = new (clangCtx)
2151+
clang::CXXThisExpr(clang::SourceLocation(), newMethod->getThisType(),
2152+
/*IsImplicit=*/false);
2153+
if (castThisToNonConstThis) {
2154+
auto baseClassPtr =
2155+
clangCtx.getPointerType(clangCtx.getRecordType(derivedClass));
2156+
clang::CastKind Kind;
2157+
clang::CXXCastPath Path;
2158+
clangSema.CheckPointerConversion(thisExpr, baseClassPtr, Kind, Path,
2159+
/*IgnoreBaseAccess=*/false,
2160+
/*Diagnose=*/true);
2161+
auto conv = clangSema.ImpCastExprToType(thisExpr, baseClassPtr, Kind,
2162+
clang::VK_PRValue, &Path);
2163+
if (!conv.isUsable())
2164+
return nullptr;
2165+
thisExpr = conv.get();
2166+
}
2167+
auto memberExpr = clangSema.BuildMemberExpr(
2168+
thisExpr, /*isArrow=*/true, clang::SourceLocation(),
2169+
clang::NestedNameSpecifierLoc(), clang::SourceLocation(),
2170+
const_cast<clang::CXXMethodDecl *>(method),
2171+
clang::DeclAccessPair::make(const_cast<clang::CXXMethodDecl *>(method),
2172+
clang::AS_public),
2173+
/*HadMultipleCandidates=*/false, method->getNameInfo(),
2174+
clangCtx.BoundMemberTy, clang::VK_PRValue, clang::OK_Ordinary);
2175+
2176+
memberCall = clangSema.BuildCallToMemberFunction(
2177+
nullptr, memberExpr, clang::SourceLocation(), args,
2178+
clang::SourceLocation());
2179+
}
21622180
if (!memberCall.isUsable())
21632181
return nullptr;
21642182
auto returnStmt =

test/Interop/Cxx/operators/Inputs/member-inline.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,15 @@ class HasStaticOperatorCallBase {
482482
static int operator()(int x) { return x + 42; }
483483
};
484484

485+
class HasStaticOperatorCallBaseNonTrivial: public NonTrivial {
486+
public:
487+
HasStaticOperatorCallBaseNonTrivial() {}
488+
HasStaticOperatorCallBaseNonTrivial(const HasStaticOperatorCallBaseNonTrivial &self) : NonTrivial(self) {}
489+
HasStaticOperatorCallBaseNonTrivial(HasStaticOperatorCallBaseNonTrivial &&self) : NonTrivial(self) {}
490+
491+
static int operator()(const NonTrivial &arg) { return arg.f + 42; }
492+
};
493+
485494
class HasStaticOperatorCallDerived : public HasStaticOperatorCallBase {};
486495

487496
class HasStaticOperatorCallWithConstOperator {

test/Interop/Cxx/operators/member-inline.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,13 @@ OperatorsTestSuite.test("HasStaticOperatorCallBase.call") {
443443
expectEqual(43, res)
444444
}
445445

446+
OperatorsTestSuite.test("HasStaticOperatorCallBase2.call") {
447+
let m = NonTrivial()
448+
let h = HasStaticOperatorCallBaseNonTrivial()
449+
let res = h(m)
450+
expectEqual(48, res)
451+
}
452+
446453
OperatorsTestSuite.test("HasStaticOperatorCallDerived.call") {
447454
let h = HasStaticOperatorCallDerived()
448455
let res = h(0)

0 commit comments

Comments
 (0)