Skip to content

Commit 28a6d24

Browse files
authored
Merge pull request #35812 from slavapestov/result-builder-invalid-var-crash
Fix a couple of crash-on-invalid situations with local variables defined inside result builders
2 parents e6f5913 + 6714723 commit 28a6d24

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,30 @@ class BuilderClosureVisitor
268268
}
269269

270270
void visitPatternBindingDecl(PatternBindingDecl *patternBinding) {
271-
// If any of the entries lacks an initializer, don't handle this node.
272-
if (!llvm::all_of(range(patternBinding->getNumPatternEntries()),
273-
[&](unsigned index) {
274-
return patternBinding->isExplicitlyInitialized(index);
275-
})) {
276-
if (!unhandledNode)
277-
unhandledNode = patternBinding;
278-
return;
271+
// Enforce some restrictions on local variables inside a result builder.
272+
for (unsigned i : range(patternBinding->getNumPatternEntries())) {
273+
// The pattern binding must have an initial value expression.
274+
if (!patternBinding->isExplicitlyInitialized(i)) {
275+
if (!unhandledNode)
276+
unhandledNode = patternBinding;
277+
return;
278+
}
279+
280+
// Each variable bound by the pattern must be stored, and cannot
281+
// have observers.
282+
SmallVector<VarDecl *, 8> variables;
283+
patternBinding->getPattern(i)->collectVariables(variables);
284+
285+
for (auto *var : variables) {
286+
if (!var->getImplInfo().isSimpleStored()) {
287+
if (!unhandledNode)
288+
unhandledNode = patternBinding;
289+
return;
290+
}
291+
292+
// Also check for invalid attributes.
293+
TypeChecker::checkDeclAttributes(var);
294+
}
279295
}
280296

281297
// If there is a constraint system, generate constraints for the pattern
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
@resultBuilder
4+
struct DummyBuilder { // expected-note 5 {{struct 'DummyBuilder' declared here}}
5+
static func buildBlock<T>(_ t: T) -> T {
6+
return t
7+
}
8+
}
9+
10+
func dummy<T>(@DummyBuilder _: () -> T) {}
11+
12+
dummy {
13+
var computedVar: Int { return 123 } // expected-error {{closure containing a declaration cannot be used with result builder 'DummyBuilder'}}
14+
()
15+
}
16+
17+
dummy {
18+
lazy var lazyVar: Int = 123 // expected-error {{closure containing a declaration cannot be used with result builder 'DummyBuilder'}}
19+
()
20+
}
21+
22+
dummy {
23+
var observedVar: Int = 123 { // expected-error {{closure containing a declaration cannot be used with result builder 'DummyBuilder'}}
24+
didSet {}
25+
}
26+
27+
()
28+
}
29+
30+
dummy {
31+
var observedVar: Int = 123 { // expected-error {{closure containing a declaration cannot be used with result builder 'DummyBuilder'}}
32+
willSet {}
33+
}
34+
35+
()
36+
}
37+
38+
@propertyWrapper struct Wrapper {
39+
var wrappedValue: Int
40+
}
41+
42+
dummy {
43+
@Wrapper var wrappedVar: Int = 123 // expected-error {{closure containing a declaration cannot be used with result builder 'DummyBuilder'}}
44+
()
45+
}
46+
47+
dummy {
48+
@resultBuilder var attributedVar: Int = 123 // expected-error {{@resultBuilder' attribute cannot be applied to this declaration}}
49+
// expected-warning@-1 {{variable 'attributedVar' was never used; consider replacing with '_' or removing it}}
50+
()
51+
}

0 commit comments

Comments
 (0)