Skip to content

Commit 4629e85

Browse files
committed
Fixes crash while instrumenting generic func body embedded in another func.
The crash was caused by attempting to add logging expressions that capture generic variables while using the outer func decl context that was not the generic decl context of the inner (generic) func. The fix "pushes" the current func decl context into body instrumenting, then "popping" the context on return. Rather than always using the top-level func decl context for all nested func bodies.
1 parent 577945d commit 4629e85

File tree

5 files changed

+57
-2
lines changed

5 files changed

+57
-2
lines changed

lib/Sema/InstrumenterSupport.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,18 @@ Expr *InstrumenterBase::buildIDArgumentExpr(std::optional<DeclNameRef> name,
142142
return new (Context) UnresolvedDeclRefExpr(*name, DeclRefKind::Ordinary,
143143
DeclNameLoc(SR.End));
144144
}
145+
146+
BraceStmt *InstrumenterBase::transformBraceStmtWithLocalDeclContext(
147+
BraceStmt *BS, DeclContext *localDC, const ParameterList *PL,
148+
bool TopLevel) {
149+
// Override TypeCheckDC for the scope of the brace stmt
150+
DeclContext *outerTypeCheckDC = TypeCheckDC;
151+
TypeCheckDC = localDC;
152+
153+
BraceStmt *transformedBS = transformBraceStmt(BS, PL, TopLevel);
154+
155+
// Restore TypeCheckDC
156+
TypeCheckDC = outerTypeCheckDC;
157+
158+
return transformedBS;
159+
}

lib/Sema/InstrumenterSupport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ class InstrumenterBase {
5252
const ParameterList *PL = nullptr,
5353
bool TopLevel = false) = 0;
5454

55+
BraceStmt *
56+
transformBraceStmtWithLocalDeclContext(BraceStmt *BS, DeclContext *localDC,
57+
const ParameterList *PL = nullptr,
58+
bool TopLevel = false);
59+
5560
/// Create an expression which retrieves a valid ModuleIdentifier or
5661
/// FileIdentifier, if available.
5762
Expr *buildIDArgumentExpr(std::optional<DeclNameRef> name, SourceRange SR);

lib/Sema/PCMacro.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ class Instrumenter : InstrumenterBase {
339339
if (auto *FD = dyn_cast<FuncDecl>(D)) {
340340
if (BraceStmt *B = FD->getTypecheckedBody()) {
341341
const ParameterList *PL = FD->getParameters();
342-
BraceStmt *NB = transformBraceStmt(B, PL);
342+
BraceStmt *NB =
343+
transformBraceStmtWithLocalDeclContext(B, /*localDC =*/FD, PL);
343344
// Since it would look strange going straight to the first line in a
344345
// function body, we throw in a before/after pointing at the function
345346
// decl at the start of the transformed body

lib/Sema/PlaygroundTransform.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ class Instrumenter : InstrumenterBase {
312312
if (BraceStmt *B = FD->getTypecheckedBody()) {
313313
const ParameterList *PL = FD->getParameters();
314314
TargetKindSetter TKS(BracePairs, BracePair::TargetKinds::Return);
315-
BraceStmt *NB = transformBraceStmt(B, PL);
315+
BraceStmt *NB =
316+
transformBraceStmtWithLocalDeclContext(B, /*localDC =*/FD, PL);
316317
if (NB != B) {
317318
FD->setBody(NB, AbstractFunctionDecl::BodyKind::TypeChecked);
318319
TypeChecker::checkFunctionEffects(FD);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// Build PlaygroundSupport module
4+
// RUN: %target-build-swift -whole-module-optimization -module-name PlaygroundSupport -emit-module-path %t/PlaygroundSupport.swiftmodule -parse-as-library -c -o %t/PlaygroundSupport.o %S/Inputs/SilentPCMacroRuntime.swift %S/Inputs/PlaygroundsRuntime.swift
5+
6+
// RUN: %target-build-swift -swift-version 5 -emit-module -Xfrontend -playground -I=%t %s
7+
// RUN: %target-build-swift -swift-version 6 -emit-module -Xfrontend -playground -I=%t %s
8+
9+
// RUN: %target-build-swift -swift-version 5 -emit-module -Xfrontend -playground -Xfrontend -pc-macro -I=%t %s
10+
// RUN: %target-build-swift -swift-version 6 -emit-module -Xfrontend -playground -Xfrontend -pc-macro -I=%t %s
11+
12+
// REQUIRES: executable_test
13+
14+
import PlaygroundSupport
15+
16+
func test1() {
17+
func buildBlock<Content>(content: Content) {
18+
content
19+
}
20+
}
21+
22+
func test2() {
23+
func buildBlock<Content>(content: Content) -> Content {
24+
content
25+
return content
26+
}
27+
}
28+
29+
func test3<Content>(_ content: Content) {
30+
func buildBlock<Content2>(_ content2: Content2) -> Content2 {
31+
return content2
32+
}
33+
}

0 commit comments

Comments
 (0)