diff --git a/include/swift/AST/DiagnosticsModuleDiffer.def b/include/swift/AST/DiagnosticsModuleDiffer.def index 7b5592e646323..894ed29998a50 100644 --- a/include/swift/AST/DiagnosticsModuleDiffer.def +++ b/include/swift/AST/DiagnosticsModuleDiffer.def @@ -96,6 +96,8 @@ ERROR(type_witness_change,none,"%0 has type witness type for %1 changing from %2 ERROR(decl_new_witness_table_entry,none,"%0 now requires %select{|no}1 new witness table entry", (StringRef, bool)) +ERROR(new_decl_without_intro,none,"%0 is a new API without @available attribute", (StringRef)) + #ifndef DIAG_NO_UNDEF # if defined(DIAG) # undef DIAG diff --git a/test/api-digester/Inputs/cake1.swift b/test/api-digester/Inputs/cake1.swift index 46acbe634a79d..21e3c09539c5c 100644 --- a/test/api-digester/Inputs/cake1.swift +++ b/test/api-digester/Inputs/cake1.swift @@ -168,3 +168,7 @@ public protocol HasMutatingMethodClone: HasMutatingMethod { mutating func foo() var bar: Int { mutating get } } + +public extension Int { + public func IntEnhancer() {} +} diff --git a/test/api-digester/Outputs/Cake-abi.txt b/test/api-digester/Outputs/Cake-abi.txt index 5ccd014fc16b9..053ab3b680ed8 100644 --- a/test/api-digester/Outputs/Cake-abi.txt +++ b/test/api-digester/Outputs/Cake-abi.txt @@ -6,6 +6,7 @@ cake1: Protocol P3 has generic signature change from <τ_0_0 : cake.P1, τ_0_0 : /* RawRepresentable Changes */ /* Removed Decls */ +Swift: Extension Int has been removed cake1: Accessor GlobalVarChangedToLet.Set() has been removed cake1: Accessor RemoveSetters.Value.Set() has been removed cake1: AssociatedType RequiementChanges.removedType has been removed @@ -56,6 +57,20 @@ cake1: Var C1.CIIns1 changes from weak to strong cake1: Var C1.CIIns2 changes from strong to weak cake1: Var GlobalLetChangedToVar changes from let to var cake1: Var GlobalVarChangedToLet changes from var to let +cake2: Accessor GlobalLetChangedToVar.Set() is a new API without @available attribute +cake2: Accessor fixedLayoutStruct2.BecomeFixedBinaryOrder.Set() is a new API without @available attribute +cake2: AssociatedType RequiementChanges.addedTypeWithDefault is a new API without @available attribute +cake2: AssociatedType RequiementChanges.addedTypeWithoutDefault is a new API without @available attribute +cake2: Class C0 is a new API without @available attribute +cake2: Class C8 is a new API without @available attribute +cake2: Constructor C1.init(_:) is a new API without @available attribute +cake2: EnumElement FrozenKind.AddedCase is a new API without @available attribute +cake2: Func RequiementChanges.addedFunc() is a new API without @available attribute +cake2: Func fixedLayoutStruct.OKChange() is a new API without @available attribute +cake2: Protocol P4 is a new API without @available attribute +cake2: Var RequiementChanges.addedVar is a new API without @available attribute +cake2: Var fixedLayoutStruct.$__lazy_storage_$_lazy_d is a new API without @available attribute +cake2: Var fixedLayoutStruct.c is a new API without @available attribute /* Fixed-layout Type changes */ cake1: EnumElement FrozenKind.Fixed in a non-resilient type changes position from 1 to 2 diff --git a/test/api-digester/Outputs/Cake.txt b/test/api-digester/Outputs/Cake.txt index 80633b05f594d..88091a9253bd2 100644 --- a/test/api-digester/Outputs/Cake.txt +++ b/test/api-digester/Outputs/Cake.txt @@ -6,6 +6,7 @@ cake1: Protocol P3 has generic signature change from ", "isABIPlaceholder": true, + "intro_Macosx": "9999", + "intro_iOS": "9999", + "intro_tvOS": "9999", + "intro_watchOS": "9999", "funcSelfKind": "NonMutating" } ], diff --git a/test/api-digester/Outputs/cake.json b/test/api-digester/Outputs/cake.json index 462416c1b4563..ebb6a6cd067b5 100644 --- a/test/api-digester/Outputs/cake.json +++ b/test/api-digester/Outputs/cake.json @@ -982,6 +982,10 @@ "moduleName": "cake", "genericSig": "", "isABIPlaceholder": true, + "intro_Macosx": "9999", + "intro_iOS": "9999", + "intro_tvOS": "9999", + "intro_watchOS": "9999", "funcSelfKind": "NonMutating" } ], diff --git a/test/api-digester/Outputs/stability-stdlib-abi.asserts.additional.swift.expected b/test/api-digester/Outputs/stability-stdlib-abi.asserts.additional.swift.expected new file mode 100644 index 0000000000000..04ccbba339084 --- /dev/null +++ b/test/api-digester/Outputs/stability-stdlib-abi.asserts.additional.swift.expected @@ -0,0 +1,7 @@ +Func _collectReferencesInsideObject(_:) is a new API without @available attribute +Func _loadDestroyTLSCounter() is a new API without @available attribute +Protocol _RuntimeFunctionCountersStats is a new API without @available attribute +Struct _GlobalRuntimeFunctionCountersState is a new API without @available attribute +Struct _ObjectRuntimeFunctionCountersState is a new API without @available attribute +Struct _RuntimeFunctionCounters is a new API without @available attribute +Func _measureRuntimeFunctionCountersDiffs(objects:_:) is a new API without @available attribute diff --git a/test/api-digester/Outputs/stability-stdlib-abi.swift.expected b/test/api-digester/Outputs/stability-stdlib-abi.swift.expected deleted file mode 100644 index dc37d5af648bb..0000000000000 --- a/test/api-digester/Outputs/stability-stdlib-abi.swift.expected +++ /dev/null @@ -1,9 +0,0 @@ -Func _cos(_:) has been removed -Func _exp(_:) has been removed -Func _exp2(_:) has been removed -Func _log(_:) has been removed -Func _log10(_:) has been removed -Func _log2(_:) has been removed -Func _nearbyint(_:) has been removed -Func _rint(_:) has been removed -Func _sin(_:) has been removed diff --git a/test/api-digester/Outputs/stability-stdlib-abi.without.asserts.swift.expected b/test/api-digester/Outputs/stability-stdlib-abi.without.asserts.swift.expected new file mode 100644 index 0000000000000..89a1face05b95 --- /dev/null +++ b/test/api-digester/Outputs/stability-stdlib-abi.without.asserts.swift.expected @@ -0,0 +1,22 @@ +// The init(signOf:magnitudeOf:) blames are false positives. They are not new APIs. +Constructor Double.init(signOf:magnitudeOf:) is a new API without @available attribute +Constructor Float.init(signOf:magnitudeOf:) is a new API without @available attribute +Constructor Float80.init(signOf:magnitudeOf:) is a new API without @available attribute + +Constructor __RawDictionaryStorage.init(coder:) is a new API without @available attribute +Constructor __RawSetStorage.init(coder:) is a new API without @available attribute +Constructor __SwiftNativeNSData.init(coder:) is a new API without @available attribute +Constructor __SwiftNativeNSDictionary.init(coder:) is a new API without @available attribute +Constructor __SwiftNativeNSSet.init(coder:) is a new API without @available attribute + +Func _cos(_:) has been removed +Func _exp(_:) has been removed +Func _exp2(_:) has been removed + +Func _log(_:) has been removed +Func _log10(_:) has been removed +Func _log2(_:) has been removed + +Func _nearbyint(_:) has been removed +Func _rint(_:) has been removed +Func _sin(_:) has been removed diff --git a/test/api-digester/stability-stdlib-abi-with-asserts.swift b/test/api-digester/stability-stdlib-abi-with-asserts.swift new file mode 100644 index 0000000000000..dd56b03ab1429 --- /dev/null +++ b/test/api-digester/stability-stdlib-abi-with-asserts.swift @@ -0,0 +1,15 @@ +// REQUIRES: OS=macosx +// REQUIRES: swift_stdlib_asserts +// RUN: %empty-directory(%t.tmp) +// mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk +// RUN: %api-digester -dump-sdk -module Swift -o %t.tmp/current-stdlib.json -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -abi -avoid-location +// RUN: %api-digester -diagnose-sdk -input-paths %S/Inputs/stdlib-stable-abi.json -input-paths %t.tmp/current-stdlib.json -abi -o %t.tmp/changes.txt -v +// RUN: %clang -E -P -x c %S/Outputs/stability-stdlib-abi.without.asserts.swift.expected -o - > %t.tmp/stability-stdlib-abi.swift.expected +// RUN: %clang -E -P -x c %S/Outputs/stability-stdlib-abi.asserts.additional.swift.expected -o - >> %t.tmp/stability-stdlib-abi.swift.expected +// RUN: %clang -E -P -x c %t.tmp/stability-stdlib-abi.swift.expected -o - | sed '/^\s*$/d' | sort > %t.tmp/stability-stdlib-abi.swift.expected.sorted +// RUN: %clang -E -P -x c %t.tmp/changes.txt -o - | sed '/^\s*$/d' | sort > %t.tmp/changes.txt.tmp +// RUN: diff -u %t.tmp/stability-stdlib-abi.swift.expected.sorted %t.tmp/changes.txt.tmp + +// The digester can incorrectly register a generic signature change when +// declarations are shuffled. rdar://problem/46618883 +// UNSUPPORTED: swift_evolve diff --git a/test/api-digester/stability-stdlib-abi.swift b/test/api-digester/stability-stdlib-abi-without-asserts.swift similarity index 79% rename from test/api-digester/stability-stdlib-abi.swift rename to test/api-digester/stability-stdlib-abi-without-asserts.swift index c6736dff3183f..85e823318d6fc 100644 --- a/test/api-digester/stability-stdlib-abi.swift +++ b/test/api-digester/stability-stdlib-abi-without-asserts.swift @@ -1,9 +1,10 @@ // REQUIRES: OS=macosx +// REQUIRES: swift_stdlib_no_asserts // RUN: %empty-directory(%t.tmp) // mkdir %t.tmp/module-cache && mkdir %t.tmp/dummy.sdk // RUN: %api-digester -dump-sdk -module Swift -o %t.tmp/current-stdlib.json -module-cache-path %t.tmp/module-cache -sdk %t.tmp/dummy.sdk -abi -avoid-location // RUN: %api-digester -diagnose-sdk -input-paths %S/Inputs/stdlib-stable-abi.json -input-paths %t.tmp/current-stdlib.json -abi -o %t.tmp/changes.txt -v -// RUN: %clang -E -P -x c %S/Outputs/stability-stdlib-abi.swift.expected -o - | sed '/^\s*$/d' | sort > %t.tmp/stability-stdlib-abi.swift.expected +// RUN: %clang -E -P -x c %S/Outputs/stability-stdlib-abi.without.asserts.swift.expected -o - | sed '/^\s*$/d' | sort > %t.tmp/stability-stdlib-abi.swift.expected // RUN: %clang -E -P -x c %t.tmp/changes.txt -o - | sed '/^\s*$/d' | sort > %t.tmp/changes.txt.tmp // RUN: diff -u %t.tmp/stability-stdlib-abi.swift.expected %t.tmp/changes.txt.tmp diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp index 2a19b98fecac7..8122d0090903b 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.cpp +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.cpp @@ -385,7 +385,15 @@ StringRef SDKNodeDecl::getScreenInfo() const { OS << "(" << HeaderName << ")"; if (!OS.str().empty()) OS << ": "; - OS << getDeclKind() << " " << getFullyQualifiedName(); + bool IsExtension = false; + if (auto *TD = dyn_cast(this)) { + IsExtension = TD->isExternal(); + } + if (IsExtension) + OS << "Extension"; + else + OS << getDeclKind(); + OS << " " << getFullyQualifiedName(); return Ctx.buffer(OS.str()); } @@ -1137,6 +1145,8 @@ static bool isABIPlaceholderRecursive(Decl *D) { } StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) { + if (!D) + return StringRef(); for (auto *ATT: D->getAttrs()) { if (auto *AVA = dyn_cast(ATT)) { if (AVA->Platform == Kind && AVA->Introduced) { @@ -1144,10 +1154,12 @@ StringRef SDKContext::getPlatformIntroVersion(Decl *D, PlatformKind Kind) { } } } - return StringRef(); + return getPlatformIntroVersion(D->getDeclContext()->getAsDecl(), Kind); } StringRef SDKContext::getLanguageIntroVersion(Decl *D) { + if (!D) + return StringRef(); for (auto *ATT: D->getAttrs()) { if (auto *AVA = dyn_cast(ATT)) { if (AVA->isLanguageVersionSpecific() && AVA->Introduced) { @@ -1155,7 +1167,7 @@ StringRef SDKContext::getLanguageIntroVersion(Decl *D) { } } } - return StringRef(); + return getLanguageIntroVersion(D->getDeclContext()->getAsDecl()); } SDKNodeInitInfo::SDKNodeInitInfo(SDKContext &Ctx, Type Ty, TypeInitInfo Info) : diff --git a/tools/swift-api-digester/ModuleAnalyzerNodes.h b/tools/swift-api-digester/ModuleAnalyzerNodes.h index 37a546ff17698..68519aafb9ad9 100644 --- a/tools/swift-api-digester/ModuleAnalyzerNodes.h +++ b/tools/swift-api-digester/ModuleAnalyzerNodes.h @@ -145,6 +145,7 @@ struct CheckerOptions { bool AbortOnModuleLoadFailure; bool PrintModule; bool SwiftOnly; + bool SkipOSCheck; StringRef LocationFilter; }; @@ -293,6 +294,9 @@ struct PlatformIntroVersion { StringRef tvos; StringRef watchos; StringRef swift; + bool hasOSAvailability() const { + return !macos.empty() || !ios.empty() || !tvos.empty() || !watchos.empty(); + } }; class SDKNodeDecl: public SDKNode { @@ -347,6 +351,7 @@ class SDKNodeDecl: public SDKNode { StringRef getScreenInfo() const; bool hasFixedBinaryOrder() const { return FixedBinaryOrder.hasValue(); } uint8_t getFixedBinaryOrder() const { return *FixedBinaryOrder; } + PlatformIntroVersion getIntroducingVersion() const { return introVersions; } virtual void jsonize(json::Output &Out) override; virtual void diagnose(SDKNode *Right) override; diff --git a/tools/swift-api-digester/ModuleDiagsConsumer.cpp b/tools/swift-api-digester/ModuleDiagsConsumer.cpp index 5fa2fb101907a..a81a79c49df46 100644 --- a/tools/swift-api-digester/ModuleDiagsConsumer.cpp +++ b/tools/swift-api-digester/ModuleDiagsConsumer.cpp @@ -44,6 +44,7 @@ static StringRef getCategoryName(uint32_t ID) { case LocalDiagID::decl_new_attr: case LocalDiagID::var_let_changed: case LocalDiagID::func_self_access_change: + case LocalDiagID::new_decl_without_intro: return "/* Decl Attribute changes */"; case LocalDiagID::default_arg_removed: case LocalDiagID::decl_type_change: diff --git a/tools/swift-api-digester/swift-api-digester.cpp b/tools/swift-api-digester/swift-api-digester.cpp index c69a93c68a0b3..7456b37540e0d 100644 --- a/tools/swift-api-digester/swift-api-digester.cpp +++ b/tools/swift-api-digester/swift-api-digester.cpp @@ -127,6 +127,12 @@ SwiftOnly("swift-only", llvm::cl::init(false), llvm::cl::cat(Category)); +static llvm::cl::opt +DisableOSChecks("disable-os-checks", + llvm::cl::desc("Skip OS related diagnostics"), + llvm::cl::init(false), + llvm::cl::cat(Category)); + static llvm::cl::opt PrintModule("print-module", llvm::cl::desc("Print module names in diagnostics"), llvm::cl::cat(Category)); @@ -1003,6 +1009,14 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { if (D->hasFixedBinaryOrder()) { D->emitDiag(diag::decl_added); } + // Diagnose the missing of @available attributes. + // Decls with @_alwaysEmitIntoClient aren't required to have an + // @available attribute. + if (!Ctx.getOpts().SkipOSCheck && + !D->getIntroducingVersion().hasOSAvailability() && + !D->hasDeclAttribute(DeclAttrKind::DAK_AlwaysEmitIntoClient)) { + D->emitDiag(diag::new_decl_without_intro); + } } } // Complain about added protocol requirements @@ -1038,7 +1052,6 @@ class PrunePass : public MatchedNodeListener, public SDKTreeDiffPass { } } } - return; case NodeMatchReason::Removed: assert(!Right); @@ -2371,6 +2384,7 @@ static CheckerOptions getCheckOpts() { Opts.LocationFilter = options::LocationFilter; Opts.PrintModule = options::PrintModule; Opts.SwiftOnly = options::SwiftOnly; + Opts.SkipOSCheck = options::DisableOSChecks; return Opts; }