Skip to content

Commit bc15343

Browse files
authored
Merge pull request #39847 from xymus/api-avail-init-properties
[Sema] Don't check availability in assigned properties initializers for -check-api-availaiblity-only mode
2 parents c209f52 + d2ec6b9 commit bc15343

11 files changed

+100
-33
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ ERROR(error_mode_cannot_emit_module_semantic_info,none,
136136
ERROR(cannot_emit_ir_skipping_function_bodies,none,
137137
"the -experimental-skip-*-function-bodies* flags do not support "
138138
"emitting IR", ())
139+
ERROR(cannot_emit_ir_checking_api_availability_only,none,
140+
"the flag -check-api-availability-only does not support "
141+
"emitting IR", ())
139142

140143
WARNING(emit_reference_dependencies_without_primary_file,none,
141144
"ignoring -emit-reference-dependencies (requires -primary-file)", ())

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5890,7 +5890,8 @@ bool hasExplicitResult(ClosureExpr *closure);
58905890
/// Emit diagnostics for syntactic restrictions within a given solution
58915891
/// application target.
58925892
void performSyntacticDiagnosticsForTarget(
5893-
const SolutionApplicationTarget &target, bool isExprStmt);
5893+
const SolutionApplicationTarget &target,
5894+
bool isExprStmt,bool disableExprAvailabiltyChecking = false);
58945895

58955896
/// Given a member of a protocol, check whether `Self` type of that
58965897
/// protocol is contextually bound to some concrete type via same-type

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,19 @@ bool ArgsToFrontendOptionsConverter::convert(
229229
if (checkUnusedSupplementaryOutputPaths())
230230
return true;
231231

232-
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction) &&
233-
(Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
234-
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
235-
Args.hasArg(
236-
OPT_experimental_skip_non_inlinable_function_bodies_without_types))) {
237-
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
238-
return true;
232+
if (FrontendOptions::doesActionGenerateIR(Opts.RequestedAction)) {
233+
if (Args.hasArg(OPT_experimental_skip_non_inlinable_function_bodies) ||
234+
Args.hasArg(OPT_experimental_skip_all_function_bodies) ||
235+
Args.hasArg(
236+
OPT_experimental_skip_non_inlinable_function_bodies_without_types)) {
237+
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_skipping_function_bodies);
238+
return true;
239+
}
240+
241+
if (Args.hasArg(OPT_check_api_availability_only)) {
242+
Diags.diagnose(SourceLoc(), diag::cannot_emit_ir_checking_api_availability_only);
243+
return true;
244+
}
239245
}
240246

241247
if (const Arg *A = Args.getLastArg(OPT_module_abi_name))

lib/Sema/MiscDiagnostics.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4732,7 +4732,8 @@ void swift::checkPatternBindingDeclAsyncUsage(PatternBindingDecl *decl) {
47324732
/// Emit diagnostics for syntactic restrictions on a given expression.
47334733
void swift::performSyntacticExprDiagnostics(const Expr *E,
47344734
const DeclContext *DC,
4735-
bool isExprStmt) {
4735+
bool isExprStmt,
4736+
bool disableExprAvailabiltyChecking) {
47364737
auto &ctx = DC->getASTContext();
47374738
TypeChecker::diagnoseSelfAssignment(E);
47384739
diagSyntacticUseRestrictions(E, DC, isExprStmt);
@@ -4744,7 +4745,7 @@ void swift::performSyntacticExprDiagnostics(const Expr *E,
47444745
diagnoseComparisonWithNaN(E, DC);
47454746
if (!ctx.isSwiftVersionAtLeast(5))
47464747
diagnoseDeprecatedWritableKeyPath(E, DC);
4747-
if (!ctx.LangOpts.DisableAvailabilityChecking)
4748+
if (!ctx.LangOpts.DisableAvailabilityChecking && !disableExprAvailabiltyChecking)
47484749
diagnoseExprAvailability(E, const_cast<DeclContext*>(DC));
47494750
if (ctx.LangOpts.EnableObjCInterop)
47504751
diagDeprecatedObjCSelectors(DC, E);

lib/Sema/MiscDiagnostics.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ namespace swift {
3434
class ValueDecl;
3535

3636
/// Emit diagnostics for syntactic restrictions on a given expression.
37-
void performSyntacticExprDiagnostics(const Expr *E, const DeclContext *DC,
38-
bool isExprStmt);
37+
void performSyntacticExprDiagnostics(
38+
const Expr *E, const DeclContext *DC,
39+
bool isExprStmt, bool disableExprAvailabiltyChecking = false);
3940

4041
/// Emit diagnostics for a given statement.
4142
void performStmtDiagnostics(const Stmt *S, DeclContext *DC);

lib/Sema/TypeCheckAccess.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,19 +1640,6 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
16401640
// "name: TheType" form, we can get better results by diagnosing the TypeRepr.
16411641
UNINTERESTING(Var)
16421642

1643-
static bool shouldCheck(Decl *D) {
1644-
if (D && D->getASTContext().LangOpts.CheckAPIAvailabilityOnly) {
1645-
// Skip whole decl if not API-public.
1646-
if (auto valueDecl = dyn_cast<const ValueDecl>(D)) {
1647-
AccessScope scope =
1648-
valueDecl->getFormalAccessScope(/*useDC*/nullptr,
1649-
/*treatUsableFromInlineAsPublic*/true);
1650-
if (!scope.isPublic())
1651-
return false;
1652-
}
1653-
}
1654-
return true;
1655-
}
16561643

16571644
/// \see visitPatternBindingDecl
16581645
void checkNamedPattern(const NamedPattern *NP,
@@ -1699,7 +1686,7 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
16991686
}
17001687

17011688
void visitPatternBindingDecl(PatternBindingDecl *PBD) {
1702-
if (!shouldCheck(PBD->getAnchoringVarDecl(0)))
1689+
if (!shouldCheckAvailability(PBD->getAnchoringVarDecl(0)))
17031690
return;
17041691

17051692
llvm::DenseSet<const VarDecl *> seenVars;
@@ -1969,8 +1956,22 @@ void swift::checkAccessControl(Decl *D) {
19691956
if (where.isImplicit())
19701957
return;
19711958

1972-
if (!DeclAvailabilityChecker::shouldCheck(D))
1959+
if (!shouldCheckAvailability(D))
19731960
return;
19741961

19751962
DeclAvailabilityChecker(where).visit(D);
19761963
}
1964+
1965+
bool swift::shouldCheckAvailability(const Decl *D) {
1966+
if (D && D->getASTContext().LangOpts.CheckAPIAvailabilityOnly) {
1967+
// Skip whole decl if not API-public.
1968+
if (auto valueDecl = dyn_cast<const ValueDecl>(D)) {
1969+
AccessScope scope =
1970+
valueDecl->getFormalAccessScope(/*useDC*/nullptr,
1971+
/*treatUsableFromInlineAsPublic*/true);
1972+
if (!scope.isPublic())
1973+
return false;
1974+
}
1975+
}
1976+
return true;
1977+
}

lib/Sema/TypeCheckAvailability.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ bool diagnoseExplicitUnavailability(
265265
/// Check if \p decl has a introduction version required by -require-explicit-availability
266266
void checkExplicitAvailability(Decl *decl);
267267

268+
/// Check if \p D needs to be checked for correct availability depending on the
269+
/// flag -check-api-availability-only.
270+
bool shouldCheckAvailability(const Decl *D);
271+
268272
} // namespace swift
269273

270274
#endif // SWIFT_SEMA_TYPE_CHECK_AVAILABILITY_H

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "MiscDiagnostics.h"
2020
#include "TypeChecker.h"
21+
#include "TypeCheckAvailability.h"
2122
#include "swift/AST/ASTVisitor.h"
2223
#include "swift/AST/ASTWalker.h"
2324
#include "swift/AST/DiagnosticSuppression.h"
@@ -272,12 +273,14 @@ class FunctionSyntacticDiagnosticWalker : public ASTWalker {
272273
} // end anonymous namespace
273274

274275
void constraints::performSyntacticDiagnosticsForTarget(
275-
const SolutionApplicationTarget &target, bool isExprStmt) {
276+
const SolutionApplicationTarget &target,
277+
bool isExprStmt, bool disableExprAvailabiltyChecking) {
276278
auto *dc = target.getDeclContext();
277279
switch (target.kind) {
278280
case SolutionApplicationTarget::Kind::expression: {
279281
// First emit diagnostics for the main expression.
280-
performSyntacticExprDiagnostics(target.getAsExpr(), dc, isExprStmt);
282+
performSyntacticExprDiagnostics(target.getAsExpr(), dc,
283+
isExprStmt, disableExprAvailabiltyChecking);
281284

282285
// If this is a for-in statement, we also need to check the where clause if
283286
// present.
@@ -400,7 +403,9 @@ TypeChecker::typeCheckExpression(
400403
// expression now.
401404
if (!cs.shouldSuppressDiagnostics()) {
402405
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
403-
performSyntacticDiagnosticsForTarget(*resultTarget, isExprStmt);
406+
performSyntacticDiagnosticsForTarget(
407+
*resultTarget, isExprStmt,
408+
options.contains(TypeCheckExprFlags::DisableExprAvailabilityChecking));
404409
}
405410

406411
resultTarget->setExpr(result);
@@ -428,8 +433,19 @@ bool TypeChecker::typeCheckBinding(
428433
initializer, DC, patternType, pattern,
429434
/*bindPatternVarsOneWay=*/false);
430435

436+
auto options = TypeCheckExprOptions();
437+
if (DC->getASTContext().LangOpts.CheckAPIAvailabilityOnly &&
438+
PBD && !DC->getAsDecl()) {
439+
// Skip checking the initializer for non-public decls when
440+
// checking the API only.
441+
auto VD = PBD->getAnchoringVarDecl(0);
442+
if (!swift::shouldCheckAvailability(VD)) {
443+
options |= TypeCheckExprFlags::DisableExprAvailabilityChecking;
444+
}
445+
}
446+
431447
// Type-check the initializer.
432-
auto resultTarget = typeCheckExpression(target);
448+
auto resultTarget = typeCheckExpression(target, options);
433449

434450
if (resultTarget) {
435451
initializer = resultTarget->getAsExpr();

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ enum class TypeCheckExprFlags {
134134
/// unchecked. This is used by source tooling functionalities such as code
135135
/// completion.
136136
LeaveClosureBodyUnchecked = 0x04,
137+
138+
/// Don't type check expressions for correct availability.
139+
DisableExprAvailabilityChecking = 0x08,
137140
};
138141

139142
using TypeCheckExprOptions = OptionSet<TypeCheckExprFlags>;

test/Sema/api-availability-only-ok.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
@available(macOS 11.0, *)
1212
public protocol NewProto {}
1313

14+
@available(macOS 11.0, *)
15+
public struct NewStruct {}
16+
1417
@available(macOS 11.0, *)
1518
public func newFunc() {}
1619

@@ -58,6 +61,10 @@ public struct Struct {
5861
private var privateVar: NewProto
5962
fileprivate var fileprivateVar: NewProto
6063

64+
internal var internalAssigned = NewStruct()
65+
private var privateAssigned = NewStruct()
66+
fileprivate var fileprivateAssigned = NewStruct()
67+
6168
@available(macOS 11.0, *)
6269
public typealias PubTA = NewProto
6370
private typealias PrivateTA = NewProto

test/Sema/api-availability-only.swift

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,19 @@
33

44
// RUN: %target-typecheck-verify-swift -module-name MyModule -target %target-cpu-apple-macosx10.15 -check-api-availability-only -enable-library-evolution
55

6+
// RUN: not %target-build-swift -emit-executable %s -g -o %t -emit-module -Xfrontend -check-api-availability-only 2>&1 | %FileCheck %s
7+
// CHECK: the flag -check-api-availability-only does not support emitting IR
8+
69
// REQUIRES: OS=macosx
710

811
@available(macOS 11.0, *)
912
public protocol NewProto {}
1013

14+
@available(macOS 11.0, *)
15+
public struct NewStruct {
16+
public init() {}
17+
}
18+
1119
@available(macOS 11.0, *)
1220
public func newFunc() {}
1321

@@ -23,14 +31,25 @@ public func apiFunc(s : NewProto) { // expected-error {{'NewProto' is only avail
2331
newFunc()
2432
}
2533

26-
// expected-note @+1 3 {{add @available attribute to enclosing}}
34+
// expected-note @+1 6 {{add @available attribute to enclosing}}
2735
@inlinable func inlinable(s : NewProto) { // expected-error {{'NewProto' is only available in macOS 11.0 or newer}}
2836

2937
// expected-note @+1 {{add 'if #available' version check}}
3038
let _: NewProto // expected-error {{'NewProto' is only available in macOS 11.0 or newer}}
3139

3240
// expected-note @+1 {{add 'if #available' version check}}
3341
newFunc() // expected-error {{'newFunc()' is only available in macOS 11.0 or newer}}
42+
43+
// expected-note @+1 {{add 'if #available' version check}}
44+
let _ = NewStruct() // expected-error {{'NewStruct' is only available in macOS 11.0 or newer}}
45+
46+
// expected-note @+2 {{add 'if #available' version check}}
47+
// expected-warning @+1 {{initialization of immutable value 'a' was never used}}
48+
let a = NewStruct() // expected-error {{'NewStruct' is only available in macOS 11.0 or newer}}
49+
50+
// expected-note @+2 {{add 'if #available' version check}}
51+
// expected-warning @+1 {{result of 'NewStruct' initializer is unused}}
52+
NewStruct() // expected-error {{'NewStruct' is only available in macOS 11.0 or newer}}
3453
}
3554

3655
// expected-note @+1 {{add @available attribute to enclosing}}
@@ -54,13 +73,18 @@ fileprivate func fileprivateFunc(s : NewProto) {
5473
newFunc()
5574
}
5675

57-
// expected-note @+1 7 {{add @available attribute to enclosing struct}}
76+
// expected-note @+1 8 {{add @available attribute to enclosing struct}}
5877
public struct Struct {
5978
public var publicVar: NewProto // expected-error {{'NewProto' is only available in macOS 11.0 or newer}}
6079
internal var internalVar: NewProto
6180
private var privateVar: NewProto
6281
fileprivate var fileprivateVar: NewProto
6382

83+
public var publicAssigned = NewStruct() // expected-error {{'NewStruct' is only available in macOS 11.0 or newer}}
84+
internal var internalAssigned = NewStruct()
85+
private var privateAssigned = NewStruct()
86+
fileprivate var fileprivateAssigned = NewStruct()
87+
6488
// expected-note @+1 {{add @available attribute to enclosing}}
6589
public typealias PubTA = NewProto // expected-error {{'NewProto' is only available in macOS 11.0 or newer}}
6690
private typealias PrivateTA = NewProto

0 commit comments

Comments
 (0)