Skip to content

Commit 11cba20

Browse files
authored
Merge pull request #75457 from kavon/6.0-warn-noop-consumes
[6.0🍒] Consume: warn about no-op consumes to be fixed
2 parents 087d201 + 82d97e3 commit 11cba20

File tree

6 files changed

+124
-5
lines changed

6 files changed

+124
-5
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7819,6 +7819,8 @@ ERROR(consume_expression_needed_for_cast,none,
78197819
"implicit conversion to %0 is consuming", (Type))
78207820
NOTE(add_consume_to_silence,none,
78217821
"add 'consume' to make consumption explicit", ())
7822+
WARNING(consume_of_bitwisecopyable_noop,none,
7823+
"'consume' applied to bitwise-copyable type %0 has no effect", (Type))
78227824
ERROR(consume_expression_not_passed_lvalue,none,
78237825
"'consume' can only be applied to a local binding ('let', 'var', or parameter)", ())
78247826
ERROR(consume_expression_partial_copyable,none,

lib/Sema/MiscDiagnostics.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,56 @@ static void diagSyntacticUseRestrictions(const Expr *E, const DeclContext *DC,
427427
consumeExpr->getSubExpr());
428428
for (auto &diag : diags)
429429
diag.emit(Ctx);
430+
431+
// As of now, SE-366 is not correctly implemented (rdar://102780553),
432+
// so warn about certain consume's being no-ops today that will no longer
433+
// be a no-op in the future once we fix this.
434+
if (auto ty = consumeExpr->getType()) {
435+
bool shouldWarn = true;
436+
437+
// Look through any load.
438+
auto *expr = consumeExpr->getSubExpr();
439+
if (auto *load = dyn_cast<LoadExpr>(expr))
440+
expr = load->getSubExpr();
441+
442+
// Don't warn if explicit ownership was provided on a parameter.
443+
// Those seem to be checked just fine in SIL.
444+
if (auto *declRef = dyn_cast<DeclRefExpr>(expr)) {
445+
if (auto *decl = declRef->getDecl()) {
446+
if (auto *paramDecl = dyn_cast<ParamDecl>(decl)) {
447+
switch (paramDecl->getSpecifier()) {
448+
case ParamSpecifier::InOut:
449+
case ParamSpecifier::Borrowing:
450+
case ParamSpecifier::Consuming:
451+
case ParamSpecifier::ImplicitlyCopyableConsuming:
452+
shouldWarn = false;
453+
break;
454+
case ParamSpecifier::Default:
455+
case ParamSpecifier::LegacyShared:
456+
case ParamSpecifier::LegacyOwned:
457+
break; // warn
458+
}
459+
}
460+
}
461+
}
462+
463+
// Only warn about obviously concrete BitwiseCopyable types, since we
464+
// know those won't get checked for consumption.
465+
if (diags.empty() &&
466+
shouldWarn &&
467+
!ty->hasError() &&
468+
!ty->hasTypeParameter() &&
469+
!ty->hasUnboundGenericType() &&
470+
!ty->hasArchetype()) {
471+
auto bitCopy = Ctx.getProtocol(KnownProtocolKind::BitwiseCopyable);
472+
if (DC->getParentModule()->checkConformance(ty, bitCopy)) {
473+
Ctx.Diags.diagnose(consumeExpr->getLoc(),
474+
diag::consume_of_bitwisecopyable_noop, ty)
475+
.fixItRemoveChars(consumeExpr->getStartLoc(),
476+
consumeExpr->getSubExpr()->getStartLoc());
477+
}
478+
}
479+
}
430480
}
431481

432482
void checkCopyExpr(CopyExpr *copyExpr) {

test/Parse/move_expr.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
var global: Int = 5
44
func testGlobal() {
5-
let _ = consume global
5+
let _ = consume global // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
66
}
77

88
func testLet() {

test/SILOptimizer/consume_operator_kills_copyable_loadable_vars.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,14 @@ func consumeInitdArray() {
725725
func isNegative(_ c: consuming Int) -> Bool { return c < 0 }
726726
func consumeInt() {
727727
var g = 0 // expected-warning{{variable 'g' was never mutated; consider changing to 'let' constant}}
728-
isNegative(consume g) // expected-warning{{result of call to 'isNegative' is unused}}
728+
// expected-error@-1 {{'g' used after consume}}
729+
730+
_ = isNegative(consume g) // expected-note {{consumed here}}
731+
// expected-warning@-1 {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
732+
733+
_ = isNegative(consume g) // expected-note {{used here}}
734+
// expected-error@-1 {{'consume' applied to value that the compiler does not support. This is a compiler bug. Please file a bug with a small example of the bug}}
735+
// expected-warning@-2 {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
729736
}
730737

731738
//////////////////////
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
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}}{{7-15=}}
31+
_ = consume point // expected-warning {{'consume' applied to bitwise-copyable type 'Point' has no effect}}{{7-15=}}
32+
_ = consume cbcg_concrete // expected-warning {{'consume' applied to bitwise-copyable type 'ConditionallyBC<Int>' has no effect}}{{7-16=}}
33+
_ = consume maybeFloat // expected-warning {{'consume' applied to bitwise-copyable type 'Float?' has no effect}}{{8-16=}}
34+
}
35+
36+
func proofOfUseAfterConsume() -> Int {
37+
let someInt = 10
38+
let y = consume someInt // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
39+
print(y)
40+
return someInt // undiagnosed use-after-consume
41+
}
42+
43+
func moreProofs(_ share: __shared Int,
44+
_ own: __owned Int,
45+
_ snd: sending Int, // expected-error {{'snd' used after consume}}
46+
_ ino: inout Int, // expected-error {{'ino' used after consume}}
47+
_ brw: borrowing Int, // expected-error {{'brw' is borrowed and cannot be consumed}}
48+
_ csm: consuming Int // expected-error {{'csm' consumed more than once}}
49+
) {
50+
_ = consume share // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
51+
_ = consume own // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
52+
let _ = (share, own)
53+
54+
_ = consume ino // expected-note {{consumed}}
55+
_ = consume brw // expected-note {{consumed}}
56+
_ = consume csm // expected-note {{consumed}}
57+
_ = consume csm // expected-note {{consumed}}
58+
_ = consume snd // expected-note {{consumed}}
59+
_ = snd // expected-note {{used}}
60+
} // expected-note {{used here}}

test/Sema/move_expr.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class Klass {
66

77
var global: Int = 5
88
func testGlobal() {
9-
let _ = consume global
9+
let _ = consume global // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
1010
}
1111

1212
func testLet() {
@@ -23,14 +23,14 @@ func testVar() {
2323
func testExprFailureLet() {
2424
let t = 5
2525
// Next line is parsed as move(t) + t
26-
let _ = consume t + t
26+
let _ = consume t + t // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
2727
}
2828

2929
func testExprFailureVar() {
3030
var t = 5
3131
t = 5
3232
// Next line is parsed as move(t) + t
33-
let _ = consume t + t
33+
let _ = consume t + t // expected-warning {{'consume' applied to bitwise-copyable type 'Int' has no effect}}
3434
}
3535

3636
func letAddressOnly<T>(_ v: T) {

0 commit comments

Comments
 (0)