Commit Graph

53 Commits

Author SHA1 Message Date
Gabor Horvath
402ad33463 [StrictMemorySafety] Check the safety of return types of calls
Previously, we skipped checking the return type of a function for safety
as we expected to warn at the use of the returned value:

  let x = returnsUnsafe()
  usesUnsafe(x) // warn here

Unfortunately, this resulted in missing some unsafe constructs that can
introduce memory safety issues when the use of the return value had a
different shape resulting in false negatives for cases like:

  return returnsUnsafe()

or

  usesUnsafe(returnsUnsafe())

This PR changes the analysis to always take return types of function
calls into account.

rdar://157237301
2025-08-05 12:16:44 +01:00
Doug Gregor
f64516b01d [Strict memory safety] "unsafe" expression never propagates unsafe outward
In the effects checker, we were propagating the "has an unsafe use
site" outside of an `unsafe` expression. The result of this is that we
would not produce a warning for silly expressions like `unsafe unsafe
ptr.pointee`, where the first (outer) `unsafe` is unnecessary. Stop
propagating that bit so we properly diagnose the spurious "unsafe".

Fixes issue #82315 / rdar://153672668.
2025-07-16 12:44:08 -07:00
Doug Gregor
35628cb503 [Strict memory safety] Fix "unsafe" checking for the for..in loop
The `$generator` variable we create for the async for..in loop is
`nonisolated(unsafe)`, so ensure that we generate an `unsafe`
expression when we use it. This uncovered some inconsistencies in how
we do `unsafe` checking for for..in loops, so fix those.

Fixes rdar://154775389.
2025-07-09 16:19:14 -07:00
Doug Gregor
6ba48f2738 [Strict memory safety] Adjust "unsafe" location for string interpolations
String interpolations can end up being unsafe in the call to
appendInterpolation when it's provided with unsafe types. Move the
location of the proposed "unsafe" out to the string interpolation
itself in these cases, which properly suppresses the warning.

Fixes rdar://151799777.
2025-06-02 12:36:36 -07:00
Doug Gregor
5c3faaaf92 Merge pull request #81884 from DougGregor/unsafe-for-loop-uses
[Strict memory safety] Show issues with unsafe constructs in the for..in loop
2025-05-30 23:28:53 -07:00
Doug Gregor
efacceeacd [Strict memory safety] Show issues with unsafe constructs in the for..in loop
We weren't showing the unsafe uses when we determine that a for..in
loop is unsafe. Do so, which generally means complaining about `next()`
being unsafe. Fixes rdar://151237127
2025-05-30 18:44:11 -07:00
Doug Gregor
9af5884555 [Strict memory safety] Improve Fix-Its for implied conformances
The Fix-It was adding @unsafe prior to the extension, which is
incorrect. Make sure we apply @unsafe at the right location for the
explicit conformance.

Fixes rdar://151800162
2025-05-30 17:41:10 -07:00
Doug Gregor
6a800c98b5 Add addition test case for "if case unsafe" 2025-05-22 11:07:13 +01:00
Doug Gregor
d5476aeda0 Improve diagnostic for unsafe call arguments
Use the argument type rather than the (potentially generic) parameter type.
2025-05-21 13:46:17 +01:00
Doug Gregor
d4dc36d2f3 [Strict memory safety] Lift "unsafe" in pattern match expressions
When an "unsafe" expression is used as the case expression, lift it up
so it also covers the synthesized matching expression (`=~`). This
eliminates some unsuppressible strict memory safety warnings.

Fixes rdar://151731850.
2025-05-21 13:46:17 +01:00
shiz
d12cb84586 [Parse] Avoid parsing unsafe expression before binary or postfix op (#81429)
rdar://150751248
2025-05-14 10:02:58 +01:00
Anthony Latsis
2cd90bdd69 AST: Quote attributes more consistently in DiagnosticsSema.def 2025-04-22 18:23:36 +01:00
Doug Gregor
b7d41a55a5 [Strict memory safety] Treat the implicit call to a 'defer' function as implicitly 'unsafe'
This eliminates stray warnings.
2025-04-19 21:57:12 -07:00
Doug Gregor
8ec52c825c [Strict memory safety] Nested types are safe/unsafe independent of their enclosing type
When determining whether a nested type is safe, don't consider whether
its enclosing type is safe. They're independent.
2025-04-19 09:49:22 -07:00
Doug Gregor
0405f61207 [Strict memory safety] Only diagnose unsafe types in the canonical type
Typealiases involving unsafe types that resolve to safe types
should not be diagnosed.
2025-04-18 18:43:27 -07:00
Doug Gregor
b182c96bd7 Print diagnostic group names by default
Print diagnostic groups as part of the LLVM printer in the same manner as the
Swift one does, always. Make `-print-diagnostic-groups` an inert option, since we
always print diagnostic group names with the `[#GroupName]` syntax.

As part of this, we no longer render the diagnostic group name as part
of the diagnostic *text*, instead leaving it up to the diagnostic
renderer to handle the category appropriately. Update all of the tests
that were depending on `-print-diagnostic-groups` putting it into the
text to instead use the `{{documentation-file=<file name>}}`
diagnostic verification syntax.
2025-03-29 15:40:56 -07:00
Doug Gregor
8a8e108cae Stop propagating @unsafe/@safe from type definitions down to their members 2025-03-27 16:48:09 -07:00
Doug Gregor
8789871035 Diagnose @safe @unsafe when used together
Fixes rdar://147943857.
2025-03-27 16:28:44 -07:00
Doug Gregor
d86f41a922 Improve Fix-It for if let x where x is a reference to an unsafe value
When we encounter unsafe code in `if let x`, we would produce a Fix-It
that would change it to the ill-formed `if let unsafe x`. Improve
tracking of the expressions that are synthesized for the right-hand
side of these conditions, so that we can produce a Fix-It that turns
this into the proper

    if let x = unsafe x

Fixes rdar://147944243.
2025-03-27 16:20:30 -07:00
Doug Gregor
90a2b3d8a0 Look through "unsafe" expressions when checking for single-value statements
We were rejecting the use of switch expressions on the right-hand side
of an assignment that was marked `unsafe`. Fixes rdar://147944753.
2025-03-27 09:49:34 -07:00
Doug Gregor
9570e1e3a7 [SE-0458] Add fix-it for removing unnecessary "unsafe" keywords 2025-03-18 13:57:16 -07:00
Doug Gregor
b9cb5ce791 [SE-0458] Disambiguate "unsafe" expression within string interpolation
String interpolation uses an end-of-file token, which we weren't
checking for. Fixes rdar://146493296
2025-03-07 15:10:27 -08:00
Doug Gregor
6cf56e9eb7 SE-0458: Disambiguate postfix expressions vs. unsafe expressions more generally
Handle call-vs-tuple and subscript-vs-collection-expr disambiguation using the
same "no trivia" rule that we used to disambiguite "unsafe.x" (which we
treat as a member access) from "unsafe .x" (which we treat as an unsafe
expression with a leading-dot member access).

Fixes rdar://146459104.
2025-03-07 10:19:26 -08:00
Doug Gregor
be7e87565c [SE-0458] Improved disambiguation for unsafe expressions
Disambiguate `unsafe` in a few more common contexts:
* Before a comma in a list of whatever form
* Before a left brace somewhere that we cannot have a closure

Fixes a few more source compatibility regressions found in the wild,
rdar://146125433.
2025-03-04 12:54:06 -08:00
Doug Gregor
a1180e570c More disambiguation for "unsafe" expressions
Fixes rdar://145870868 / #79704
2025-02-28 14:46:42 -08:00
Doug Gregor
c7f9f2ee3a Rename "Unsafe" diagnostic group to "StrictMemorySafety"
This lines up with the feature name and is more consistent. Thank you,
Anthony, for the suggestion.
2025-02-27 16:21:11 -08:00
Doug Gregor
0c130a995c Make test robust against strict memory safety changes to the standard library 2025-02-26 14:28:22 -08:00
Doug Gregor
939d4d7d91 [SE-0458] Disambiguate "unsafe" expression and for..in effect
Port over the disambiguation code we already had in the new Swift parser
to the existing C++ parser for the "unsafe" expression and for..in effect.
2025-02-26 13:03:55 -08:00
Doug Gregor
b7b5a2a19d [SE-0458] Enable unsafe expressions / attributes / for..in effects by default
With the acceptance of SE-0458, allow the use of unsafe expressions, the
@safe and @unsafe attributes, and the `unsafe` effect on the for..in loop
in all Swift code.

Introduce the `-strict-memory-safety` flag detailed in the proposal to
enable strict memory safety checking. This enables a new class of
feature, an optional feature (that is *not* upcoming or experimental),
and which can be detected via `hasFeature(StrictMemorySafety)`.
2025-02-26 12:30:07 -08:00
Doug Gregor
50801f9c05 [SE-0458] Implement "unsafe" effect for the for-in loop
Memory unsafety in the iteration part of the for-in loop (i.e., the part
that works on the iterator) can be covered by the "unsafe" effect on
the for..in loop, before the pattern.
2025-02-23 22:50:39 -08:00
Doug Gregor
2de9f4a8f5 [Strict safety] Stop complaining about unsafe signatures
Since we infer unsafety from a use of a declaration that involves unsafe types
in its signature, there isn't a reason to require @unsafe on declaration to
restate it. This matches recent revisions of SE-0458.
2025-02-15 22:02:22 -08:00
Doug Gregor
02ada804f1 More temporary test fixes 2025-02-10 17:10:52 -08:00
Doug Gregor
05113a69fb Fixup test case based on limitations of the existing implementation 2025-02-10 16:08:37 -08:00
Doug Gregor
929836d212 Fix Fix-it location 2025-02-10 08:26:17 -08:00
Doug Gregor
4139430560 @safe functions, properties, and subscripts "cover" certain unsafe arguments
When calling an explicitly-@safe function or subscript, or accessing an
explicitly-@safe property, the direct arguments to that operation can be
considered safe if they are references to local variables or are references
to types.

This brings the implementation in line with the recent adjustments to the
proposal within the review.
2025-02-08 10:18:12 -08:00
Doug Gregor
bd237c7daf Make sure we aren't requiring local let/var to be labeled @unsafe 2025-01-23 07:47:20 -08:00
Doug Gregor
b3f2f00588 Suggest both @unsafe and @safe Fix-Its for unsafe types in signature 2025-01-23 07:47:19 -08:00
Doug Gregor
4395537fa0 Introduce the @safe attribute as described in the opt-in safety checking proposal 2025-01-23 07:47:17 -08:00
Doug Gregor
2fc9ac08ca Handle autoclosures for 'unsafe' effects checking 2025-01-11 12:43:43 -08:00
Doug Gregor
fc632b2c53 Check 'unsafe' within keypaths 2025-01-11 12:43:43 -08:00
Doug Gregor
d6c020d843 Diagnose 'unsafe' within explicit references to types in expressions 2025-01-11 12:43:43 -08:00
Doug Gregor
446474499a Diagnose unsafe sequences in the for..in loop
The `unsafe` goes on the sequence expression, e.g.,

    for x in unsafe mySequence { ... }
2025-01-11 12:43:42 -08:00
Doug Gregor
d787c0fab3 Extend effects checking to the various expressions that reference declarations
Only "unsafe" checking is affected here.
2025-01-11 12:43:42 -08:00
Doug Gregor
37bfa1998e Tighten up checking for uses of unsafe conformances
Check for unsafe conformances for type erasure and opaque type
erasure.

This also uncovered an issue where we were making every conformance of
an unsafe type to an unsafe protocol @unsafe implicitly, even though
that's not really what we want.
2025-01-11 12:43:41 -08:00
Doug Gregor
f14baef7f4 Ensure that we record the @unsafe for conformances introduced via extensions 2025-01-11 12:43:40 -08:00
Doug Gregor
8bb5bbedbc Implement an unsafe expression to cover uses of unsafe constructs
Introduce an `unsafe` expression akin to `try` and `await` that notes
that there are unsafe constructs in the expression to the right-hand
side. Extend the effects checker to also check for unsafety along with
throwing and async operations. This will result in diagnostics like
the following:

    10 |   func sum() -> Int {
    11 |     withUnsafeBufferPointer { buffer in
    12 |       let value = buffer[0]
       |                   |     `- note: reference to unsafe subscript 'subscript(_:)'
       |                   |- warning: expression uses unsafe constructs but is not marked with 'unsafe'
       |                   `- note: reference to parameter 'buffer' involves unsafe type 'UnsafeBufferPointer<Int>'
    13 |       tryWithP(X())
    14 |       return fastAdd(buffer.baseAddress, buffer.count)

These will come with a Fix-It that inserts `unsafe` into the proper
place. There's also a warning that appears when `unsafe` doesn't cover
any unsafe code, making it easier to clean up extraneous `unsafe`.

This approach requires that `@unsafe` be present on any declaration
that involves unsafe constructs within its signature. Outside of the
signature, the `unsafe` expression is used to identify unsafe code.
2025-01-10 10:39:14 -08:00
Doug Gregor
29f23bb66a Improve diagnostics for uses of unsafe declarations in functions
Instead of producing a warning for each use of an unsafe entity,
collect all of the uses of unsafe constructs within a given function
and batch them together in a single diagnostic at the function level
that tells you what you can do (add `@unsafe` or `@safe(unchecked)`,
depending on whether all unsafe uses were in the definition), plus
notes identifying every unsafe use within that declaration. The new
diagnostic renderer nicely collects together in a single snippet, so
it's easier to reason about.

Here's an example from the embedded runtime that previously would have
been 6 separate warnings, each with 1-2 notes:

```
swift/stdlib/public/core/EmbeddedRuntime.swift:397:13: warning: global function 'swift_retainCount' involves unsafe code; use '@safe(unchecked)' to assert that the code is memory-safe
395 |
396 | @_cdecl("swift_retainCount")
397 | public func swift_retainCount(object: Builtin.RawPointer) -> Int {
    |             `- warning: global function 'swift_retainCount' involves unsafe code; use '@safe(unchecked)' to assert that the code is memory-safe
398 |   if !isValidPointerForNativeRetain(object: object) { return 0 }
399 |   let o = UnsafeMutablePointer<HeapObject>(object)
    |           |                              `- note: call to unsafe initializer 'init(_:)'
    |           `- note: reference to unsafe generic struct 'UnsafeMutablePointer'
400 |   let refcount = refcountPointer(for: o)
    |                  |                    `- note: reference to let 'o' involves unsafe type 'UnsafeMutablePointer<HeapObject>'
    |                  `- note: call to global function 'refcountPointer(for:)' involves unsafe type 'UnsafeMutablePointer<Int>'
401 |   return loadAcquire(refcount) & HeapObject.refcountMask
    |          |           `- note: reference to let 'refcount' involves unsafe type 'UnsafeMutablePointer<Int>'
    |          `- note: call to global function 'loadAcquire' involves unsafe type 'UnsafeMutablePointer<Int>'
402 | }
403 |
```

Note that we have lost a little bit of information, because we no
longer produce "unsafe declaration was here" notes pointing back at
things like `UnsafeMutablePointer` or `recountPointer(for:)`. However,
strict memory safety tends to be noisy to turn on, so it's worth
losing a little bit of easily-recovered information to gain some
brevity.
2024-12-20 07:34:51 -08:00
Doug Gregor
a98a653aee Ensure that @safe(unchecked) works within variable initializers 2024-12-14 21:47:43 -08:00
Doug Gregor
f49c594f7a Fix attribute insertion location in the presence of "static" and a modifier
We were incorrectly ignoring the "static" because it's not in the
DeclAttributes list.
2024-12-14 21:47:43 -08:00
Doug Gregor
836192b585 Correctly handle @safe on accessors 2024-12-14 21:47:43 -08:00