diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 61e6daea34647..a3cd562731c76 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -462,6 +462,9 @@ namespace swift { /// Diagnose implicit 'override'. bool WarnImplicitOverrides = false; + /// Diagnose use of declarations that are soft-deprecated. + bool WarnSoftDeprecated = false; + /// Diagnose uses of NSCoding with classes that have unstable mangled names. bool EnableNSKeyedArchiverDiagnostics = true; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 48566a6bb9c23..d99e1c1f6444f 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -838,6 +838,11 @@ def warn_implicit_overrides : Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>, HelpText<"Warn about implicit overrides of protocol members">; +def warn_soft_deprecated : + Flag<["-"], "warn-soft-deprecated">, + Flags<[FrontendOption, DoesNotAffectIncrementalBuild, HelpHidden]>, + HelpText<"Warn when soft-deprecated declarations are referenced">; + def typo_correction_limit : Separate<["-"], "typo-correction-limit">, Flags<[FrontendOption, HelpHidden]>, MetaVarName<"">, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 3403c9db39c4d..b0bffc68f2be1 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1168,6 +1168,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.WarnImplicitOverrides = Args.hasArg(OPT_warn_implicit_overrides); + Opts.WarnSoftDeprecated = Args.hasArg(OPT_warn_soft_deprecated); + Opts.EnableNSKeyedArchiverDiagnostics = Args.hasFlag(OPT_enable_nskeyedarchiver_diagnostics, OPT_disable_nskeyedarchiver_diagnostics, diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 1e52d6657158c..631a75e18ad00 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -2214,9 +2214,17 @@ void TypeChecker::diagnosePotentialUnavailability( } const AvailableAttr *TypeChecker::getDeprecated(const Decl *D) { - if (auto *Attr = D->getAttrs().getDeprecated(D->getASTContext())) + auto &Ctx = D->getASTContext(); + if (auto *Attr = D->getAttrs().getDeprecated(Ctx)) return Attr; + if (Ctx.LangOpts.WarnSoftDeprecated) { + // When -warn-soft-deprecated is specified, treat any declaration that is + // deprecated in the future as deprecated. + if (auto *Attr = D->getAttrs().getSoftDeprecated(Ctx)) + return Attr; + } + // Treat extensions methods as deprecated if their extension // is deprecated. DeclContext *DC = D->getDeclContext(); diff --git a/test/Sema/availability_soft_deprecated.swift b/test/Sema/availability_soft_deprecated.swift new file mode 100644 index 0000000000000..2bb9cc628a6eb --- /dev/null +++ b/test/Sema/availability_soft_deprecated.swift @@ -0,0 +1,46 @@ +// RUN: %target-typecheck-verify-swift +// RUN: %target-typecheck-verify-swift -warn-soft-deprecated -verify-additional-prefix soft-deprecated- + +// REQUIRES: OS=macosx || OS=ios || OS=tvos || OS=watchos || OS=xros + +@available(*, deprecated) +func alwaysDeprecated() {} + +@available(macOS, deprecated: 1.0) +@available(iOS, deprecated: 1.0) +@available(tvOS, deprecated: 1.0) +@available(watchOS, deprecated: 1.0) +@available(visionOS, deprecated: 1.0) +func deprecatedEarly() {} + +@available(macOS, deprecated: 10000) +@available(iOS, deprecated: 10000) +@available(tvOS, deprecated: 10000) +@available(watchOS, deprecated: 10000) +@available(visionOS, deprecated: 10000) +func deprecatedFarFuture() {} + +protocol Proto {} +struct HasSoftDeprecatedConformanceToProto {} + +@available(macOS, deprecated: 10000) +@available(iOS, deprecated: 10000) +@available(tvOS, deprecated: 10000) +@available(watchOS, deprecated: 10000) +@available(visionOS, deprecated: 10000) +extension HasSoftDeprecatedConformanceToProto: Proto {} + +func test() { + alwaysDeprecated() // expected-warning {{'alwaysDeprecated()' is deprecated}} + deprecatedEarly() // expected-warning {{'deprecatedEarly()' was deprecated in}} + deprecatedFarFuture() // expected-soft-deprecated-warning {{'deprecatedFarFuture()' was deprecated in}} + let _: any Proto = HasSoftDeprecatedConformanceToProto() // expected-soft-deprecated-warning {{conformance of 'HasSoftDeprecatedConformanceToProto' to 'Proto' was deprecated in}} +} + +@available(*, deprecated) +func testDeprecated() { + alwaysDeprecated() + deprecatedEarly() + deprecatedFarFuture() + let _: any Proto = HasSoftDeprecatedConformanceToProto() +}