Skip to content

Commit b510541

Browse files
committed
Consume: warn about no-op consumes to be fixed
As of now, SE-366 is not correctly implemented with respect to concrete, bitwise-copyable types like `Int`. Writing `consume someInt` doesn't actually consume the variable binding as it should, meaning code that should be flagged as having a use-after-consume is being silently permitted: ```swift let someInt = 10 let y = consume someInt print(someInt) // no error! ``` This has been a problem since Swift 5.9. Eventually we plan to fix this issue, which means code previously doing the above would become an error. To help people get ready for the fix, start warning people that these consumes are actually no-ops and suggest removing them until the intended behavior is actually enforced in the future. resolves rdar://127081103
1 parent 5230b19 commit b510541

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7749,6 +7749,9 @@ ERROR(consume_expression_needed_for_cast,none,
77497749
"implicit conversion to %0 is consuming", (Type))
77507750
NOTE(add_consume_to_silence,none,
77517751
"add 'consume' to make consumption explicit", ())
7752+
WARNING(consume_of_bitwisecopyable_noop,none,
7753+
"'consume' applied to bitwise-copyable type %0 "
7754+
"has no effect currently, but will in the future", (Type))
77527755
ERROR(consume_expression_not_passed_lvalue,none,
77537756
"'consume' can only be applied to a local binding ('let', 'var', or parameter)", ())
77547757
ERROR(consume_expression_partial_copyable,none,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,30 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
437437
consumeExpr->getSubExpr());
438438
for (auto &diag : diags)
439439
diag.emit(Ctx);
440+
441+
// As of now, SE-366 is not correctly implemented (rdar://102780553),
442+
// so warn about certain consume's being no-ops today that will no longer
443+
// be a no-op in the future once we fix this.
444+
if (auto ty = consumeExpr->getType()) {
445+
// Only warn about obviously concrete BitwiseCopyable types, since we
446+
// know those won't get checked for consumption.
447+
//
448+
// Generic bitwise-copyable types do get properly checked, since they're
449+
// address-only in SIL, so we do not mapTypeIntoContext here.
450+
if (diags.empty() &&
451+
!ty->hasError() &&
452+
!ty->hasTypeParameter() &&
453+
!ty->hasUnboundGenericType() &&
454+
!ty->hasArchetype()) {
455+
auto bitCopy = Ctx.getProtocol(KnownProtocolKind::BitwiseCopyable);
456+
if (DC->getParentModule()->checkConformance(ty, bitCopy)) {
457+
Ctx.Diags.diagnose(consumeExpr->getLoc(),
458+
diag::consume_of_bitwisecopyable_noop, ty)
459+
.fixItRemoveChars(consumeExpr->getStartLoc(),
460+
consumeExpr->getSubExpr()->getStartLoc());
461+
}
462+
}
463+
}
440464
}
441465

442466
void checkCopyExpr(CopyExpr *copyExpr) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-emit-sil %s -verify -sil-verify-all
2+
3+
struct Point {
4+
let x: Float
5+
let y: Float
6+
}
7+
8+
struct ConditionallyBC<T> {
9+
var t: T
10+
}
11+
extension ConditionallyBC: BitwiseCopyable where T: BitwiseCopyable {}
12+
13+
func test<T, BCG: BitwiseCopyable>(_ t: T, // expected-error {{'t' is borrowed and cannot be consumed}}
14+
_ bcg: BCG, // expected-error {{'bcg' is borrowed and cannot be consumed}}
15+
_ cbcg_generic: ConditionallyBC<BCG>, // expected-error {{'cbcg_generic' is borrowed and cannot be consumed}}
16+
_ maybeBCG: BCG?, // expected-error {{'maybeBCG' is borrowed and cannot be consumed}}
17+
_ maybeT: T?, // expected-error {{'maybeT' is borrowed and cannot be consumed}}
18+
_ anyBC: any BitwiseCopyable, // expected-error {{'anyBC' is borrowed and cannot be consumed}}
19+
_ x: Int,
20+
_ point: Point,
21+
_ cbcg_concrete: ConditionallyBC<Int>,
22+
_ maybeFloat: Float?) {
23+
_ = consume t // expected-note {{consumed here}}
24+
_ = consume bcg // expected-note {{consumed here}}
25+
_ = consume cbcg_generic // expected-note {{consumed here}}
26+
_ = consume maybeBCG // expected-note {{consumed here}}
27+
_ = consume maybeT // expected-note {{consumed here}}
28+
_ = consume anyBC // expected-note {{consumed here}}
29+
30+
_ = consume x // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect currently, but will in the future}}{{7-15=}}
31+
_ = consume point // expected-warning {{'consume' applied to bitwise-copyable type 'Point' has no effect currently, but will in the future}}{{7-15=}}
32+
_ = consume cbcg_concrete // expected-warning {{'consume' applied to bitwise-copyable type 'ConditionallyBC<Int>' has no effect currently, but will in the future}}{{7-16=}}
33+
_ = consume maybeFloat // expected-warning {{'consume' applied to bitwise-copyable type 'Float?' has no effect currently, but will in the future}}{{8-16=}}
34+
}

0 commit comments

Comments
 (0)