From 79e3542277c5aac2493f0fec60b4e0f6557e7701 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Thu, 23 Oct 2025 14:43:09 -0700 Subject: [PATCH] [Diagnostics] Replace diagnostics' 'DefaultIgnore' option with a corresponding option on diagnostic groups This brings this control in line with other diagnostic controls we have which operate on a per-group level. 'DefaultIgnoreWarnings' diagnostic group option applies to all warnings belonging to a certain diagnostic group. The inheritance rules are: - Marking a diagnostic group as 'DefaultIgnoreWarnings' means warnings belonging to this group will not be emitted by-default - Warnings belonging to sub-groups of this group will also not be emitted by-default - Enabling a 'DefaultIgnoreWarnings' group (with '-Werror','-Wwarning', etc.) means warnings belonging to this group will be emitted. - Warnings belonging to sub-groups of this group will also be emitted. - Warnings belonging to super-groups of this group will not be affected. --- .../swift/AST/DefineDiagnosticGroupsMacros.h | 3 +- include/swift/AST/DiagnosticEngine.h | 50 +++++--- include/swift/AST/DiagnosticGroups.def | 107 +++++++++--------- include/swift/AST/DiagnosticGroups.h | 38 ++++++- include/swift/AST/DiagnosticsFrontend.def | 4 +- include/swift/AST/DiagnosticsSIL.def | 12 +- include/swift/AST/DiagnosticsSema.def | 26 ++--- lib/AST/DiagnosticEngine.cpp | 54 +++++---- lib/AST/DiagnosticGroups.cpp | 9 +- lib/Sema/PerformanceHints.cpp | 18 +-- lib/Sema/TypeCheckEmbedded.cpp | 9 +- test/diagnostics/default-ignore-groups.swift | 26 +++++ 12 files changed, 215 insertions(+), 141 deletions(-) create mode 100644 test/diagnostics/default-ignore-groups.swift diff --git a/include/swift/AST/DefineDiagnosticGroupsMacros.h b/include/swift/AST/DefineDiagnosticGroupsMacros.h index cc778beb9a3c0..ea6cc67e919f5 100644 --- a/include/swift/AST/DefineDiagnosticGroupsMacros.h +++ b/include/swift/AST/DefineDiagnosticGroupsMacros.h @@ -28,10 +28,11 @@ // Declares a diagnostic group. // Parameters: // Name - group name as it appears in DiagGroupID enum and DiagGroupInfo.name +// Option - attribute applying to members of this diagnostic group // DocsFile - file with a human readable description for the group located in // userdocs/diagnostic_groups #ifndef GROUP -#define GROUP(Name, DocsFile) +#define GROUP(Name, Option, DocsFile) #endif // GROUP_LINK macro: diff --git a/include/swift/AST/DiagnosticEngine.h b/include/swift/AST/DiagnosticEngine.h index 5cb88a4fd822a..e382ffbaf0de2 100644 --- a/include/swift/AST/DiagnosticEngine.h +++ b/include/swift/AST/DiagnosticEngine.h @@ -57,7 +57,7 @@ namespace swift { /// this enumeration type that uniquely identifies it. enum class DiagID : uint32_t; - enum class DiagGroupID : uint16_t; + enum class DiagGroupID : uint32_t; /// Describes a diagnostic along with its argument types. /// @@ -633,6 +633,14 @@ namespace swift { /// escalated to errors. llvm::BitVector warningsAsErrors; + /// Track which diagnostic group (`DiagGroupID`) warnings should be ignored. + llvm::BitVector ignoredDiagnosticGroups; + + /// For compiler-internal purposes only, track which diagnostics should + /// be ignored completely. For example, this is used by LLDB to + /// suppress certain errors in expression evaluation. + llvm::BitVector compilerIgnoredDiagnostics; + /// Whether a fatal error has occurred bool fatalErrorOccurred = false; @@ -642,9 +650,6 @@ namespace swift { /// Track the previous emitted Behavior, useful for notes DiagnosticBehavior previousBehavior = DiagnosticBehavior::Unspecified; - /// Track which diagnostics should be ignored. - llvm::BitVector ignoredDiagnostics; - friend class DiagnosticStateRAII; public: @@ -708,17 +713,28 @@ namespace swift { fatalErrorOccurred = false; } - /// Set whether a diagnostic should be ignored. - void setIgnoredDiagnostic(DiagID id, bool ignored) { - ignoredDiagnostics[(unsigned)id] = ignored; + /// Set whether a diagnostic group should be ignored. + void setIgnoredDiagnosticGroup(DiagGroupID id, bool ignored) { + ignoredDiagnosticGroups[(unsigned)id] = ignored; + } + + /// Query whether a specific diagnostic group is ignored. + bool isIgnoredDiagnosticGroup(DiagGroupID id) const { + return ignoredDiagnosticGroups[(unsigned)id]; } - bool isIgnoredDiagnostic(DiagID id) const { - return ignoredDiagnostics[(unsigned)id]; + /// Set a specific diagnostic to be ignored by the compiler. + void compilerInternalIgnoreDiagnostic(DiagID id) { + compilerIgnoredDiagnostics[(unsigned)id] = true; } + /// Query whether a specific diagnostic group and *all* + /// of its subgroups are ignored. + bool isIgnoredDiagnosticGroupTree(DiagGroupID id) const; + void swap(DiagnosticState &other) { - std::swap(showDiagnosticsAfterFatalError, other.showDiagnosticsAfterFatalError); + std::swap(showDiagnosticsAfterFatalError, + other.showDiagnosticsAfterFatalError); std::swap(suppressWarnings, other.suppressWarnings); std::swap(suppressNotes, other.suppressNotes); std::swap(suppressRemarks, other.suppressRemarks); @@ -726,7 +742,7 @@ namespace swift { std::swap(fatalErrorOccurred, other.fatalErrorOccurred); std::swap(anyErrorOccurred, other.anyErrorOccurred); std::swap(previousBehavior, other.previousBehavior); - std::swap(ignoredDiagnostics, other.ignoredDiagnostics); + std::swap(ignoredDiagnosticGroups, other.ignoredDiagnosticGroups); } private: @@ -966,12 +982,16 @@ namespace swift { localization = diag::LocalizationProducer::producerFor(locale, path); } - void ignoreDiagnostic(DiagID id) { - state.setIgnoredDiagnostic(id, true); + bool isIgnoredDiagnosticGroup(DiagGroupID id) const { + return state.isIgnoredDiagnosticGroup(id); + } + + bool isIgnoredDiagnosticGroupTree(DiagGroupID id) const { + return state.isIgnoredDiagnosticGroupTree(id); } - bool isIgnoredDiagnostic(DiagID id) const { - return state.isIgnoredDiagnostic(id); + void ignoreDiagnostic(DiagID id) { + state.compilerInternalIgnoreDiagnostic(id); } void resetHadAnyError() { diff --git a/include/swift/AST/DiagnosticGroups.def b/include/swift/AST/DiagnosticGroups.def index 4263134a35cbd..df6783474e66c 100644 --- a/include/swift/AST/DiagnosticGroups.def +++ b/include/swift/AST/DiagnosticGroups.def @@ -35,63 +35,64 @@ #define DEFINE_DIAGNOSTIC_GROUPS_MACROS #include "swift/AST/DefineDiagnosticGroupsMacros.h" -// GROUP(Name, DocsFile) -// GROUP_LINK(Parent, Child) +// GROUP(Name,Option,DocsFile) +// GROUP_LINK(Parent,Child) -GROUP(no_group, "") +GROUP(no_group,none,"") -GROUP(ActorIsolatedCall, "actor-isolated-call") -GROUP(AlwaysAvailableDomain, "always-available-domain") -GROUP(AvailabilityUnrecognizedName, "availability-unrecognized-name") -GROUP(ClangDeclarationImport, "clang-declaration-import") -GROUP(CompilationCaching, "compilation-caching") -GROUP(ConformanceIsolation, "conformance-isolation") -GROUP(ForeignReferenceType, "foreign-reference-type") -GROUP(DeprecatedDeclaration, "deprecated-declaration") -GROUP(DynamicCallable, "dynamic-callable-requirements") -GROUP(DynamicExclusivity, "dynamic-exclusivity") -GROUP(EmbeddedRestrictions, "embedded-restrictions") -GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version") -GROUP(ExclusivityViolation, "exclusivity-violation") -GROUP(ExistentialAny, "existential-any") -GROUP(ExistentialMemberAccess, "existential-member-access-limitations") -GROUP(ExistentialType, "existential-type") -GROUP(ImplementationOnlyDeprecated, "implementation-only-deprecated") -GROUP(IsolatedConformances, "isolated-conformances") -GROUP(MemberImportVisibility, "member-import-visibility") -GROUP(MissingModuleOnKnownPaths, "missing-module-on-known-paths") -GROUP(ModuleNotTestable, "module-not-testable") -GROUP(ModuleVersionMissing, "module-version-missing") -GROUP(MultipleInheritance, "multiple-inheritance") -GROUP(MutableGlobalVariable, "mutable-global-variable") -GROUP(NominalTypes, "nominal-types") -GROUP(NonisolatedNonsendingByDefault, "nonisolated-nonsending-by-default") -GROUP(OpaqueTypeInference, "opaque-type-inference") -GROUP(PerformanceHints, "performance-hints") -GROUP(PreconcurrencyImport, "preconcurrency-import") -GROUP(PropertyWrappers, "property-wrapper-requirements") -GROUP(ProtocolTypeNonConformance, "protocol-type-non-conformance") -GROUP(RegionIsolation, "region-isolation") -GROUP(ResultBuilderMethods, "result-builder-methods") -GROUP(ReturnTypeImplicitCopy, "return-type-implicit-copy") -GROUP(SemanticCopies, "semantic-copies") -GROUP(SendableClosureCaptures, "sendable-closure-captures") -GROUP(SendableMetatypes, "sendable-metatypes") -GROUP(SendingClosureRisksDataRace, "sending-closure-risks-data-race") -GROUP(SendingRisksDataRace, "sending-risks-data-race") -GROUP(StrictLanguageFeatures, "strict-language-features") -GROUP(StrictMemorySafety, "strict-memory-safety") -GROUP(StringInterpolationConformance, "string-interpolation-conformance") -GROUP(TemporaryPointers, "temporary-pointers") -GROUP(TrailingClosureMatching, "trailing-closure-matching") -GROUP(UnknownWarningGroup, "unknown-warning-group") -GROUP(WeakMutability, "weak-mutability") +GROUP(ActorIsolatedCall,none,"actor-isolated-call") +GROUP(AlwaysAvailableDomain,none,"always-available-domain") +GROUP(AvailabilityUnrecognizedName,none,"availability-unrecognized-name") +GROUP(ClangDeclarationImport,none,"clang-declaration-import") +GROUP(CompilationCaching,none,"compilation-caching") +GROUP(ConformanceIsolation,none,"conformance-isolation") +GROUP(ForeignReferenceType,none,"foreign-reference-type") +GROUP(DeprecatedDeclaration,none,"deprecated-declaration") +GROUP(DynamicExclusivity,DefaultIgnoreWarnings,"dynamic-exclusivity") +GROUP(DynamicCallable,none,"dynamic-callable-requirements") +GROUP(EmbeddedRestrictions,DefaultIgnoreWarnings,"embedded-restrictions") +GROUP(ErrorInFutureSwiftVersion,none,"error-in-future-swift-version") +GROUP(ExclusivityViolation,none,"exclusivity-violation") +GROUP(ExistentialAny,none,"existential-any") +GROUP(ExistentialMemberAccess,none,"existential-member-access-limitations") +GROUP(ExistentialType,none,"existential-type") +GROUP(ImplementationOnlyDeprecated,none,"implementation-only-deprecated") +GROUP(IsolatedConformances,none,"isolated-conformances") +GROUP(MemberImportVisibility,none,"member-import-visibility") +GROUP(MissingModuleOnKnownPaths,none,"missing-module-on-known-paths") +GROUP(ModuleNotTestable,none,"module-not-testable") +GROUP(ModuleVersionMissing,none,"module-version-missing") +GROUP(MultipleInheritance,none,"multiple-inheritance") +GROUP(MutableGlobalVariable,none,"mutable-global-variable") +GROUP(NominalTypes,none,"nominal-types") +GROUP(NonisolatedNonsendingByDefault,none,"nonisolated-nonsending-by-default") +GROUP(OpaqueTypeInference,none,"opaque-type-inference") +GROUP(PerformanceHints,DefaultIgnoreWarnings,"performance-hints") +GROUP(PreconcurrencyImport,DefaultIgnoreWarnings,"preconcurrency-import") +GROUP(PropertyWrappers,none,"property-wrapper-requirements") +GROUP(ProtocolTypeNonConformance,none,"protocol-type-non-conformance") +GROUP(RegionIsolation,none,"region-isolation") +GROUP(ResultBuilderMethods,none,"result-builder-methods") +GROUP(ReturnTypeImplicitCopy,none,"return-type-implicit-copy") +GROUP(SendableClosureCaptures,none,"sendable-closure-captures") +GROUP(SendableMetatypes,none,"sendable-metatypes") +GROUP(SemanticCopies,DefaultIgnoreWarnings,"semantic-copies") +GROUP(SendingClosureRisksDataRace,none,"sending-closure-risks-data-race") +GROUP(SendingRisksDataRace,none,"sending-risks-data-race") +GROUP(StrictLanguageFeatures,none,"strict-language-features") +GROUP(UnrecognizedStrictLanguageFeatures,DefaultIgnoreWarnings,"strict-language-features") +GROUP(StrictMemorySafety,none,"strict-memory-safety") +GROUP(StringInterpolationConformance,none,"string-interpolation-conformance") +GROUP(TemporaryPointers,none,"temporary-pointers") +GROUP(TrailingClosureMatching,none,"trailing-closure-matching") +GROUP(UnknownWarningGroup,none,"unknown-warning-group") +GROUP(WeakMutability,none,"weak-mutability") -GROUP_LINK(PerformanceHints, ExistentialType) -GROUP_LINK(PerformanceHints, ReturnTypeImplicitCopy) +GROUP_LINK(PerformanceHints,ExistentialType) +GROUP_LINK(PerformanceHints,ReturnTypeImplicitCopy) -GROUP_LINK(RegionIsolation, SendingClosureRisksDataRace) -GROUP_LINK(RegionIsolation, SendingRisksDataRace) +GROUP_LINK(RegionIsolation,SendingClosureRisksDataRace) +GROUP_LINK(RegionIsolation,SendingRisksDataRace) #define UNDEFINE_DIAGNOSTIC_GROUPS_MACROS #include "swift/AST/DefineDiagnosticGroupsMacros.h" diff --git a/include/swift/AST/DiagnosticGroups.h b/include/swift/AST/DiagnosticGroups.h index 48e2144580d92..7b5e36313d305 100644 --- a/include/swift/AST/DiagnosticGroups.h +++ b/include/swift/AST/DiagnosticGroups.h @@ -24,16 +24,25 @@ #include namespace swift { +enum class DiagnosticGroupOptions { + /// No options. + none, + + /// The diagnostic warnings belonging to this group should be ignored by default, + /// but will be re-enabled by various warning options (-Wwarning, -Werror). + DefaultIgnoreWarnings, +}; + enum class DiagID : uint32_t; -enum class DiagGroupID : uint16_t { -#define GROUP(Name, Version) Name, +enum class DiagGroupID : uint32_t { +#define GROUP(Name, Option, DocsFile) Name, #include "swift/AST/DiagnosticGroups.def" }; constexpr const auto DiagGroupsCount = [] { size_t count = 0; -#define GROUP(Name, Version) ++count; +#define GROUP(Name, Option, DocsFile) ++count; #include "DiagnosticGroups.def" return count; }(); @@ -45,9 +54,30 @@ struct DiagGroupInfo { llvm::ArrayRef supergroups; llvm::ArrayRef subgroups; llvm::ArrayRef diagnostics; + bool defaultIgnoreWarnings : 1; + + constexpr DiagGroupInfo(DiagGroupID groupID, std::string_view name, + std::string_view documentationFile, + llvm::ArrayRef supergroups, + llvm::ArrayRef subgroups, + llvm::ArrayRef diagnostics, + bool defaultIgnoreWarnings) + : id(groupID), name(name), documentationFile(documentationFile), + supergroups(supergroups), subgroups(subgroups), diagnostics(diagnostics), + defaultIgnoreWarnings(defaultIgnoreWarnings) {} + + constexpr DiagGroupInfo(DiagGroupID groupID, std::string_view name, + std::string_view documentationFile, + DiagnosticGroupOptions opts, + llvm::ArrayRef supergroups, + llvm::ArrayRef subgroups, + llvm::ArrayRef diagnostics) + : DiagGroupInfo(groupID, name, documentationFile, supergroups, + subgroups, diagnostics, + opts == DiagnosticGroupOptions::DefaultIgnoreWarnings) {} void traverseDepthFirst( - llvm::function_ref func) const; + llvm::function_ref func) const; }; extern const std::array diagnosticGroupsInfo; diff --git a/include/swift/AST/DiagnosticsFrontend.def b/include/swift/AST/DiagnosticsFrontend.def index fde382b745ff1..a993412954110 100644 --- a/include/swift/AST/DiagnosticsFrontend.def +++ b/include/swift/AST/DiagnosticsFrontend.def @@ -40,12 +40,12 @@ WARNING(warning_upcoming_feature_on_by_default, none, "upcoming feature '%0' is already enabled as of Swift version %1", (StringRef, unsigned)) -GROUPED_WARNING(unrecognized_feature, StrictLanguageFeatures, DefaultIgnore, +GROUPED_WARNING(unrecognized_feature, UnrecognizedStrictLanguageFeatures, none, "'%0' is not a recognized " "%select{experimental|upcoming}1 feature", (StringRef, bool)) -GROUPED_WARNING(feature_not_experimental, StrictLanguageFeatures, DefaultIgnore, +GROUPED_WARNING(feature_not_experimental, UnrecognizedStrictLanguageFeatures, none, "'%0' is not an experimental feature, " "use -%select{disable|enable}1-upcoming-feature instead", (StringRef, bool)) diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 2dce5cb21ebdd..90846e4e3fc58 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -435,18 +435,18 @@ NOTE(performance_called_from,none, "called from here", ()) // ManualOwnership diagnostics -GROUPED_WARNING(manualownership_copy,SemanticCopies,DefaultIgnore, +GROUPED_WARNING(manualownership_copy,SemanticCopies,none, "implicit 'copy' happens here; please report this vague diagnostic as a bug", ()) -GROUPED_WARNING(manualownership_copy_happened,SemanticCopies,DefaultIgnore, +GROUPED_WARNING(manualownership_copy_happened,SemanticCopies,none, "accessing %0 may produce a copy; write 'copy' to acknowledge or 'consume' to elide", (Identifier)) -GROUPED_WARNING(manualownership_copy_demanded,SemanticCopies,DefaultIgnore, +GROUPED_WARNING(manualownership_copy_demanded,SemanticCopies,none, "independent copy of %0 is required here; write 'copy' to acknowledge or 'consume' to elide", (Identifier)) -GROUPED_WARNING(manualownership_copy_captured,SemanticCopies,DefaultIgnore, +GROUPED_WARNING(manualownership_copy_captured,SemanticCopies,none, "closure capture of '%0' requires independent copy of it; write [%0 = copy %0] in the closure's capture list to acknowledge", (StringRef)) -GROUPED_WARNING(manualownership_exclusivity,DynamicExclusivity,DefaultIgnore, +GROUPED_WARNING(manualownership_exclusivity,DynamicExclusivity,none, "exclusive access here will be checked at runtime; please report this vague diagnostic as a bug", ()) -GROUPED_WARNING(manualownership_exclusivity_named,DynamicExclusivity,DefaultIgnore, +GROUPED_WARNING(manualownership_exclusivity_named,DynamicExclusivity,none, "accessing %0 here may incur runtime exclusivity check%1", (Identifier, StringRef)) // 'transparent' diagnostics diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index ee76990cb0812..e5c7bfd91efa4 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -2845,7 +2845,7 @@ WARNING(add_predates_concurrency_import,none, "'Sendable'-related %select{warnings|errors}0 from module %1" "%select{| as warnings}0", (bool, Identifier)) GROUPED_WARNING(remove_predates_concurrency_import,PreconcurrencyImport, - DefaultIgnore, + none, "'@preconcurrency' on module %0 has no effect", (Identifier)) WARNING(remove_public_import,none, "public import of %0 was not used in public declarations or inlinable code", @@ -8648,18 +8648,18 @@ GROUPED_ERROR(weak_unowned_in_embedded_swift, EmbeddedRestrictions, none, (ReferenceOwnership)) GROUPED_WARNING(untyped_throws_in_embedded_swift, EmbeddedRestrictions, - DefaultIgnore, + none, "untyped throws is not available in Embedded Swift; add a thrown error type with '(type)'", ()) GROUPED_WARNING(generic_nonfinal_in_embedded_swift, EmbeddedRestrictions, - DefaultIgnore, + none, "generic %kind0 in a class %select{must be 'final'|cannot be 'required'}1 in Embedded Swift", (const Decl *, bool)) GROUPED_WARNING(use_generic_member_of_existential_in_embedded_swift, - EmbeddedRestrictions, DefaultIgnore, + EmbeddedRestrictions, none, "cannot use generic %kind0 on a value of type %1 in Embedded Swift", (const Decl *, Type)) GROUPED_WARNING(dynamic_cast_involving_protocol_in_embedded_swift, - EmbeddedRestrictions, DefaultIgnore, + EmbeddedRestrictions, none, "cannot perform a dynamic cast to a type involving %kind0 in Embedded Swift", (const Decl *)) @@ -8978,33 +8978,33 @@ ERROR(conformance_repression_only_on_struct_class_enum,none, // MARK: Swift Performance hints //===----------------------------------------------------------------------===// -GROUPED_WARNING(perf_hint_function_returns_array,ReturnTypeImplicitCopy,DefaultIgnore, +GROUPED_WARNING(perf_hint_function_returns_array,ReturnTypeImplicitCopy,none, "Performance: %0 returns a%select{ dictionary|n array}1, leading to implicit copies. " "Consider using an 'inout' parameter instead.", (const FuncDecl *, bool)) -GROUPED_WARNING(perf_hint_closure_returns_array,ReturnTypeImplicitCopy,DefaultIgnore, +GROUPED_WARNING(perf_hint_closure_returns_array,ReturnTypeImplicitCopy,none, "Performance: closure returns a%select{ dictionary|n array}0, leading to implicit copies. " "Consider using an 'inout' parameter instead.", (bool)) -GROUPED_WARNING(perf_hint_param_expects_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_param_expects_existential,ExistentialType,none, "Performance: %0 expects an existential, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", (const ParamDecl*)) -GROUPED_WARNING(perf_hint_func_returns_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_func_returns_existential,ExistentialType,none, "Performance: %0 returns an existential, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", (const FuncDecl*)) -GROUPED_WARNING(perf_hint_closure_returns_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_closure_returns_existential,ExistentialType,none, "Performance: closure returns an existential, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", ()) -GROUPED_WARNING(perf_hint_var_uses_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_var_uses_existential,ExistentialType,none, "Performance: %0 uses an existential, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", (const VarDecl *)) -GROUPED_WARNING(perf_hint_any_pattern_uses_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_any_pattern_uses_existential,ExistentialType,none, "Performance: declaration uses an existential, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", ()) -GROUPED_WARNING(perf_hint_typealias_uses_existential,ExistentialType,DefaultIgnore, +GROUPED_WARNING(perf_hint_typealias_uses_existential,ExistentialType,none, "Performance: %0 aliases an existential type, leading to heap allocation, reference counting, " "and dynamic dispatch. Consider using generic constraints or concrete types instead.", (const TypeAliasDecl *)) diff --git a/lib/AST/DiagnosticEngine.cpp b/lib/AST/DiagnosticEngine.cpp index 31f3275e7d5fb..620019f587d68 100644 --- a/lib/AST/DiagnosticEngine.cpp +++ b/lib/AST/DiagnosticEngine.cpp @@ -77,11 +77,6 @@ enum class DiagnosticOptions { /// A diagnostic warning about an unused element. NoUsage, - - /// The diagnostic should be ignored by default, but will be re-enabled - /// by various warning options (-Wwarning, -Werror). This only makes sense - /// for warnings. - DefaultIgnore, }; struct StoredDiagnosticInfo { DiagnosticKind kind : 2; @@ -90,17 +85,16 @@ struct StoredDiagnosticInfo { bool isAPIDigesterBreakage : 1; bool isDeprecation : 1; bool isNoUsage : 1; - bool defaultIgnore : 1; DiagGroupID groupID; constexpr StoredDiagnosticInfo(DiagnosticKind k, bool firstBadToken, bool fatal, bool isAPIDigesterBreakage, bool deprecation, bool noUsage, - bool defaultIgnore, DiagGroupID groupID) + DiagGroupID groupID) : kind(k), pointsToFirstBadToken(firstBadToken), isFatal(fatal), isAPIDigesterBreakage(isAPIDigesterBreakage), isDeprecation(deprecation), isNoUsage(noUsage), - defaultIgnore(defaultIgnore), groupID(groupID) {} + groupID(groupID) {} constexpr StoredDiagnosticInfo(DiagnosticKind k, DiagnosticOptions opts, DiagGroupID groupID) : StoredDiagnosticInfo(k, @@ -109,7 +103,6 @@ struct StoredDiagnosticInfo { opts == DiagnosticOptions::APIDigesterBreakage, opts == DiagnosticOptions::Deprecation, opts == DiagnosticOptions::NoUsage, - opts == DiagnosticOptions::DefaultIgnore, groupID) {} }; } // end anonymous namespace @@ -154,14 +147,29 @@ static constexpr const char *const fixItStrings[] = { }; DiagnosticState::DiagnosticState() { - // Initialize our ignored diagnostics to defaults - ignoredDiagnostics.reserve(NumDiagIDs); - for (const auto &info : storedDiagnosticInfos) { - ignoredDiagnostics.push_back(info.defaultIgnore); - } + // Initialize ignored diagnostic groups to defaults + ignoredDiagnosticGroups.resize(DiagGroupsCount); + // Ensure that for each `DefaultIgnoreWarnings` group, + // we propagate this behavior to its child groups. + for (const auto &groupInfo : diagnosticGroupsInfo) + if (groupInfo.defaultIgnoreWarnings) + getDiagGroupInfoByID(groupInfo.id).traverseDepthFirst([&](auto group) { + ignoredDiagnosticGroups[(unsigned)group.id] = true; + }); // Initialize warningsAsErrors to default warningsAsErrors.resize(DiagGroupsCount); + + // Initialize compilerIgnoredDiagnostics + compilerIgnoredDiagnostics.resize(NumDiagIDs); +} + +bool DiagnosticState::isIgnoredDiagnosticGroupTree(DiagGroupID id) const { + bool anyEnabled = false; + getDiagGroupInfoByID(id).traverseDepthFirst([&](auto group) { + anyEnabled |= !isIgnoredDiagnosticGroup(group.id); + }); + return !anyEnabled; } Diagnostic::Diagnostic(DiagID ID) @@ -597,10 +605,8 @@ void DiagnosticEngine::setWarningsAsErrorsRules( if (auto groupID = getDiagGroupIDByName(name); groupID && *groupID != DiagGroupID::no_group) { getDiagGroupInfoByID(*groupID).traverseDepthFirst([&](auto group) { - state.setWarningsAsErrorsForDiagGroupID(*groupID, isEnabled); - for (DiagID diagID : group.diagnostics) { - state.setIgnoredDiagnostic(diagID, false); - } + state.setWarningsAsErrorsForDiagGroupID(group.id, isEnabled); + state.setIgnoredDiagnosticGroup(group.id, false); }); } else { unknownGroups.push_back(std::string(name)); @@ -1343,14 +1349,16 @@ DiagnosticState::determineBehavior(const Diagnostic &diag) const { if (!showDiagnosticsAfterFatalError && lvl != DiagnosticBehavior::Note) lvl = DiagnosticBehavior::Ignore; - // 3) If the user ignored this specific diagnostic, follow that - if (ignoredDiagnostics[(unsigned)diag.getID()]) - lvl = DiagnosticBehavior::Ignore; + // Handle compiler-internal ignored diagnostics + if (compilerIgnoredDiagnostics[(unsigned)diag.getID()]) + lvl = DiagnosticBehavior::Ignore; - // 4) If the user substituted a different behavior for this behavior, apply + // 3) If the user substituted a different behavior for this warning, apply // that change if (lvl == DiagnosticBehavior::Warning) { - if (getWarningsAsErrorsForDiagGroupID(diag.getGroupID())) + if (isIgnoredDiagnosticGroup(diag.getGroupID())) + lvl = DiagnosticBehavior::Ignore; + else if (getWarningsAsErrorsForDiagGroupID(diag.getGroupID())) lvl = DiagnosticBehavior::Error; if (suppressWarnings) lvl = DiagnosticBehavior::Ignore; diff --git a/lib/AST/DiagnosticGroups.cpp b/lib/AST/DiagnosticGroups.cpp index e714cbd58d937..40a499e355848 100644 --- a/lib/AST/DiagnosticGroups.cpp +++ b/lib/AST/DiagnosticGroups.cpp @@ -68,7 +68,7 @@ constexpr const auto diagnosticGroupConnections = [] { constexpr auto diagnosticsCount = std::get<2>(sizes); // Declare all edges -#define GROUP(Name, DocsFile) \ +#define GROUP(Name, Option, DocsFile) \ std::array \ Name##_supergroups{}; \ std::array \ @@ -92,7 +92,7 @@ constexpr const auto diagnosticGroupConnections = [] { #include "swift/AST/DiagnosticsAll.def" // Produce the resulting structure with all the edges -#define GROUP(Name, DocsFile) \ +#define GROUP(Name, Option, DocsFile) \ GroupConnections(Name##_supergroups, Name##_subgroups, Name##_diagnostics), return std::tuple{ #include "swift/AST/DiagnosticGroups.def" @@ -100,7 +100,7 @@ constexpr const auto diagnosticGroupConnections = [] { }(); std::unordered_map nameToIDMap{ -#define GROUP(Name, DocsFile) {#Name, DiagGroupID::Name}, +#define GROUP(Name, Option, DocsFile) {#Name, DiagGroupID::Name}, #include "swift/AST/DiagnosticGroups.def" }; @@ -119,11 +119,12 @@ void traverseDepthFirst(DiagGroupID id, } // end anonymous namespace constexpr const std::array diagnosticGroupsInfo{ -#define GROUP(Name, DocsFile) \ +#define GROUP(Name, Option, DocsFile) \ DiagGroupInfo{ \ DiagGroupID::Name, \ #Name, \ DocsFile, \ + DiagnosticGroupOptions::Option, \ llvm::ArrayRef( \ std::get<(size_t)DiagGroupID::Name>(diagnosticGroupConnections) \ .supergroups), \ diff --git a/lib/Sema/PerformanceHints.cpp b/lib/Sema/PerformanceHints.cpp index 79e110d68da92..14c6313f0adf4 100644 --- a/lib/Sema/PerformanceHints.cpp +++ b/lib/Sema/PerformanceHints.cpp @@ -21,6 +21,7 @@ #include "swift/AST/ASTWalker.h" #include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsFrontend.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Evaluator.h" #include "swift/AST/Expr.h" @@ -30,22 +31,7 @@ using namespace swift; bool swift::performanceHintDiagnosticsEnabled(ASTContext &ctx) { - return !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_closure_returns_array.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_function_returns_array.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_param_expects_existential.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_func_returns_existential.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_closure_returns_existential.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_var_uses_existential.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_any_pattern_uses_existential.ID) || - !ctx.Diags.isIgnoredDiagnostic( - diag::perf_hint_typealias_uses_existential.ID); + return !ctx.Diags.isIgnoredDiagnosticGroupTree(DiagGroupID::PerformanceHints); } namespace { diff --git a/lib/Sema/TypeCheckEmbedded.cpp b/lib/Sema/TypeCheckEmbedded.cpp index 96bde91d40663..39a4bd1849329 100644 --- a/lib/Sema/TypeCheckEmbedded.cpp +++ b/lib/Sema/TypeCheckEmbedded.cpp @@ -17,6 +17,7 @@ #include "TypeCheckEmbedded.h" #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" +#include "swift/AST/DiagnosticGroups.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Effects.h" #include "swift/AST/Expr.h" @@ -46,11 +47,11 @@ swift::shouldDiagnoseEmbeddedLimitations(const DeclContext *dc, SourceLoc loc, return defaultEmbeddedLimitationForError(dc, loc); } - // Check one of the Embedded restriction diagnostics that is ignored by - // default. If it's still ignored, we won't diagnose anything. - // limitations. + // Check if the Embedded restriction diagnostics, which are ignored by + // default, have been enabled. If it's still ignored, we won't diagnose + // anything. limitations. auto &diags = dc->getASTContext().Diags; - if (diags.isIgnoredDiagnostic(diag::untyped_throws_in_embedded_swift.ID)) + if (diags.isIgnoredDiagnosticGroup(DiagGroupID::EmbeddedRestrictions)) return std::nullopt; #if SWIFT_BUILD_SWIFT_SYNTAX diff --git a/test/diagnostics/default-ignore-groups.swift b/test/diagnostics/default-ignore-groups.swift new file mode 100644 index 0000000000000..3a3a6454fd0ed --- /dev/null +++ b/test/diagnostics/default-ignore-groups.swift @@ -0,0 +1,26 @@ +// RUN: %empty-directory(%t) + +// Ignore `ReturnTypeImplicitCopy` warnings by-default, because its parent group (`PerformanceHints`) is marked `DefaultIgnoreWarnings` +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -verify + +// Ensure enabled with `-Wwarning` +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -Wwarning ReturnTypeImplicitCopy -verify -verify-additional-prefix warnonly- + +// Ensure enabled with `-Wwarning` on the parent group +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -Wwarning PerformanceHints -verify -verify-additional-prefix warnonly- + +// Ensure enabled with `-Werror` +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -Werror ReturnTypeImplicitCopy -verify -verify-additional-prefix erronly- + +// Ensure enabled with `-Werror` on the parent group +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -Werror PerformanceHints -verify -verify-additional-prefix erronly- + +// Ensure enabling sibling group does not enable this group +// RUN: %target-swift-frontend -typecheck %s -diagnostic-style llvm -verify -Werror ExistentialType + + +func foo() -> [Int] { +// expected-erronly-error@-1 {{Performance: 'foo()' returns an array, leading to implicit copies. Consider using an 'inout' parameter instead}} +// expected-warnonly-warning@-2 {{Performance: 'foo()' returns an array, leading to implicit copies. Consider using an 'inout' parameter instead}} + return [1,2,3,4,5,6] +}