Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,15 @@
#include "swift/AST/LayoutConstraintKind.h"
#include "swift/AST/PlatformKind.h"
#include "swift/Basic/BasicBridging.h"
#include "swift/Basic/WarningGroupBehavior.h"

#ifdef NOT_COMPILED_WITH_SWIFT_PURE_BRIDGING_MODE
#include "swift/AST/Attr.h"
#include "swift/AST/Decl.h"
#endif

#include <utility>

SWIFT_BEGIN_NULLABILITY_ANNOTATIONS

namespace llvm {
Expand Down Expand Up @@ -1104,11 +1107,36 @@ BridgedSwiftNativeObjCRuntimeBaseAttr_createParsed(BridgedASTContext cContext,
swift::SourceRange range,
swift::Identifier name);

SWIFT_NAME("BridgedWarnAttr.createParsed(_:atLoc:range:diagGroupName:behavior:reason:)")
BridgedWarnAttr
BridgedWarnAttr_createParsed(BridgedASTContext cContext,
swift::SourceLoc atLoc,
swift::SourceRange range,
swift::Identifier diagGroupName,
swift::WarningGroupBehavior behavior,
BridgedStringRef reason);

enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedNonSendableKind {
BridgedNonSendableKindSpecific,
BridgedNonSendableKindAssumed,
};

SWIFT_NAME("BridgedWarningGroupBehaviorRule.getGroupName(self:)")
BridgedStringRef BridgedWarningGroupBehaviorRule_getGroupName(BridgedWarningGroupBehaviorRule rule);

SWIFT_NAME("BridgedWarningGroupBehaviorRule.getBehavior(self:)")
swift::WarningGroupBehavior
BridgedWarningGroupBehaviorRule_getBehavior(BridgedWarningGroupBehaviorRule rule);


SWIFT_NAME("getDiagnosticGroupLinksCount()")
SwiftInt
BridgedDiagnosticGroupLinks_getCount();

SWIFT_NAME("getDiagnosticGroupLink(at:)")
std::pair<BridgedStringRef, BridgedStringRef>
BridgedDiagnosticGroupLinks_getLink(SwiftInt index);

SWIFT_NAME("BridgedNonSendableAttr.createParsed(_:atLoc:range:kind:)")
BridgedNonSendableAttr BridgedNonSendableAttr_createParsed(
BridgedASTContext cContext, swift::SourceLoc atLoc,
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ASTBridgingWrappers.def
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ AST_BRIDGING_WRAPPER_NONNULL(CustomAttribute)
AST_BRIDGING_WRAPPER_NULLABLE(ArgumentList)
AST_BRIDGING_WRAPPER_NULLABLE(AvailabilitySpec)
AST_BRIDGING_WRAPPER_CONST_NONNULL(AvailabilityMacroMap)
AST_BRIDGING_WRAPPER_NULLABLE(WarningGroupBehaviorRule)
AST_BRIDGING_WRAPPER_NONNULL(PoundAvailableInfo)
AST_BRIDGING_WRAPPER_NONNULL(LifetimeEntry)

Expand Down
34 changes: 34 additions & 0 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "swift/AST/AvailabilityRange.h"
#include "swift/AST/ConcreteDeclRef.h"
#include "swift/AST/DeclNameLoc.h"
#include "swift/AST/DiagnosticGroups.h"
#include "swift/AST/Identifier.h"
#include "swift/AST/KnownProtocols.h"
#include "swift/AST/LifetimeDependence.h"
Expand All @@ -41,6 +42,7 @@
#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/UUID.h"
#include "swift/Basic/Version.h"
#include "swift/Basic/WarningGroupBehavior.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -3641,6 +3643,38 @@ class NonexhaustiveAttr : public DeclAttribute {
}
};

class WarnAttr : public DeclAttribute {
public:
WarnAttr(DiagGroupID DiagnosticGroupID, WarningGroupBehavior Behavior,
std::optional<StringRef> Reason, SourceLoc AtLoc, SourceRange Range,
bool Implicit)
: DeclAttribute(DeclAttrKind::Warn, AtLoc, Range, Implicit),
DiagnosticBehavior(Behavior), DiagnosticGroupID(DiagnosticGroupID),
Reason(Reason) {}

WarnAttr(DiagGroupID DiagnosticGroupID, WarningGroupBehavior Behavior, bool Implicit)
: WarnAttr(DiagnosticGroupID, Behavior, std::nullopt, SourceLoc(),
SourceRange(), Implicit) {}

WarningGroupBehavior DiagnosticBehavior;
DiagGroupID DiagnosticGroupID;
const std::optional<StringRef> Reason;

static bool classof(const DeclAttribute *DA) {
return DA->getKind() == DeclAttrKind::Warn;
}

WarnAttr *clone(ASTContext &ctx) const {
return new (ctx) WarnAttr(DiagnosticGroupID, DiagnosticBehavior, Reason,
AtLoc, Range, isImplicit());
}

bool isEquivalent(const WarnAttr *other,
Decl *attachedTo) const {
return Reason == other->Reason;
}
};


/// The kind of unary operator, if any.
enum class UnaryOperatorKind : uint8_t { None, Prefix, Postfix };
Expand Down
8 changes: 7 additions & 1 deletion include/swift/AST/DeclAttr.def
Original file line number Diff line number Diff line change
Expand Up @@ -902,12 +902,18 @@ DECL_ATTR(specialized, Specialized,
AllowMultipleAttributes | LongAttribute | UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
172)


SIMPLE_DECL_ATTR(_unsafeSelfDependentResult, UnsafeSelfDependentResult,
OnAccessor,
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove | EquivalentInABIAttr,
173)

LAST_DECL_ATTR(UnsafeSelfDependentResult)
DECL_ATTR(warn, Warn,
OnFunc | OnConstructor | OnDestructor | OnSubscript | OnVar | OnNominalType | OnExtension | OnAccessor | OnImport,
AllowMultipleAttributes | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
174)

LAST_DECL_ATTR(Warn)

#undef DECL_ATTR_ALIAS
#undef CONTEXTUAL_DECL_ATTR_ALIAS
Expand Down
109 changes: 61 additions & 48 deletions include/swift/AST/DiagnosticEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "swift/Basic/PrintDiagnosticNamesMode.h"
#include "swift/Basic/Statistic.h"
#include "swift/Basic/Version.h"
#include "swift/Basic/WarningAsErrorRule.h"
#include "swift/Basic/WarningGroupBehaviorRule.h"
#include "swift/Localization/LocalizationFormat.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -612,6 +612,10 @@ namespace swift {
ArrayRef<DiagnosticArgument> Args);
};


using WarningGroupBehaviorMap =
std::unordered_map<swift::DiagGroupID, WarningGroupBehaviorRule>;

/// Class to track, map, and remap diagnostic severity and fatality
///
class DiagnosticState {
Expand All @@ -628,13 +632,13 @@ namespace swift {
/// Don't emit any remarks
bool suppressRemarks = false;

/// A mapping from `DiagGroupID` identifiers to Boolean values indicating
/// whether warnings belonging to the respective diagnostic groups should be
/// escalated to errors.
llvm::BitVector warningsAsErrors;

/// Track which diagnostic group (`DiagGroupID`) warnings should be ignored.
llvm::BitVector ignoredDiagnosticGroups;
/// A mapping from `DiagGroupID` identifiers to `WarningGroupBehaviorRule`
/// values indicating how warnings belonging to the respective diagnostic groups
/// should be emitted. While there is duplication between this data structure
/// being a map keyed with `DiagGroupID` and containing a rule object which also
/// contains a matching `DiagGroupID`, this significantly simplifies bridging
/// values of this map to Swift clients.
WarningGroupBehaviorMap warningGroupBehaviorMap;

/// For compiler-internal purposes only, track which diagnostics should
/// be ignored completely. For example, this is used by LLDB to
Expand All @@ -657,7 +661,8 @@ namespace swift {

/// Figure out the Behavior for the given diagnostic, taking current
/// state such as fatality into account.
DiagnosticBehavior determineBehavior(const Diagnostic &diag) const;
DiagnosticBehavior determineBehavior(const Diagnostic &diag,
SourceManager &sourceMgr) const;

/// Updates the diagnostic state for a diagnostic to emit.
void updateFor(DiagnosticBehavior behavior);
Expand All @@ -684,45 +689,37 @@ namespace swift {
void setSuppressRemarks(bool val) { suppressRemarks = val; }
bool getSuppressRemarks() const { return suppressRemarks; }

/// Sets whether warnings belonging to the diagnostic group identified by
/// `id` should be escalated to errors.
void setWarningsAsErrorsForDiagGroupID(DiagGroupID id, bool value) {
warningsAsErrors[(unsigned)id] = value;
/// Configure the command-line warning group handling
/// rules (`-Werrr`,`-Wwarning`,`-warnings-as-errors`)
void setWarningGroupControlRules(
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules);

/// Add an individual command-line warning group behavior
void addWarningGroupControl(const DiagGroupID &groupID,
WarningGroupBehavior behavior) {
warningGroupBehaviorMap.insert_or_assign(
groupID, WarningGroupBehaviorRule(behavior, groupID));
}

/// Returns a Boolean value indicating whether warnings belonging to the
/// diagnostic group identified by `id` should be escalated to errors.
bool getWarningsAsErrorsForDiagGroupID(DiagGroupID id) const {
return warningsAsErrors[(unsigned)id];
const WarningGroupBehaviorMap&
getWarningGroupBehaviorControlMap() const {
return warningGroupBehaviorMap;
}

/// Whether all warnings should be upgraded to errors or not.
void setAllWarningsAsErrors(bool value) {
// This works as intended because every diagnostic belongs to either a
// custom group or the top-level `DiagGroupID::no_group`, which is also
// a group.
if (value) {
warningsAsErrors.set();
} else {
warningsAsErrors.reset();
}
const std::vector<const WarningGroupBehaviorRule*>
getWarningGroupBehaviorControlRefArray() const {
std::vector<const WarningGroupBehaviorRule*> ruleRefArray;
ruleRefArray.reserve(warningGroupBehaviorMap.size());
for (const auto &rule: warningGroupBehaviorMap)
ruleRefArray.push_back(&rule.second);
return ruleRefArray;
}

void resetHadAnyError() {
anyErrorOccurred = false;
fatalErrorOccurred = false;
}

/// 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];
}

/// Set a specific diagnostic to be ignored by the compiler.
void compilerInternalIgnoreDiagnostic(DiagID id) {
compilerIgnoredDiagnostics[(unsigned)id] = true;
Expand All @@ -738,11 +735,10 @@ namespace swift {
std::swap(suppressWarnings, other.suppressWarnings);
std::swap(suppressNotes, other.suppressNotes);
std::swap(suppressRemarks, other.suppressRemarks);
std::swap(warningsAsErrors, other.warningsAsErrors);
std::swap(warningGroupBehaviorMap, other.warningGroupBehaviorMap);
std::swap(fatalErrorOccurred, other.fatalErrorOccurred);
std::swap(anyErrorOccurred, other.anyErrorOccurred);
std::swap(previousBehavior, other.previousBehavior);
std::swap(ignoredDiagnosticGroups, other.ignoredDiagnosticGroups);
}

private:
Expand All @@ -752,6 +748,13 @@ namespace swift {

DiagnosticState(DiagnosticState &&) = default;
DiagnosticState &operator=(DiagnosticState &&) = default;

/// If this diagnostic is a warning belonging to a diagnostic group,
/// figure out if there is a source-level (`@warn`) control for this group
/// for this diagnostic's source location.
std::optional<DiagnosticBehavior>
determineUserControlledWarningBehavior(const Diagnostic &diag,
SourceManager &sourceMgr) const;
};

/// A lightweight reference to a diagnostic that's been fully applied to
Expand Down Expand Up @@ -951,7 +954,20 @@ namespace swift {
/// Rules are applied in order they appear in the vector.
/// In case the vector contains rules affecting the same diagnostic ID
/// the last rule wins.
void setWarningsAsErrorsRules(const std::vector<WarningAsErrorRule> &rules);
void setWarningGroupControlRules(
const llvm::SmallVector<WarningGroupBehaviorRule, 4> &rules) {
state.setWarningGroupControlRules(rules);
}

const WarningGroupBehaviorMap&
getWarningGroupBehaviorControlMap() const {
return state.getWarningGroupBehaviorControlMap();
}

const std::vector<const WarningGroupBehaviorRule*>
getWarningGroupBehaviorControlRefArray() const {
return state.getWarningGroupBehaviorControlRefArray();
}

/// Whether to print diagnostic names after their messages
void setPrintDiagnosticNamesMode(PrintDiagnosticNamesMode val) {
Expand Down Expand Up @@ -982,13 +998,9 @@ namespace swift {
localization = diag::LocalizationProducer::producerFor(locale, path);
}

bool isIgnoredDiagnosticGroup(DiagGroupID id) const {
return state.isIgnoredDiagnosticGroup(id);
}

bool isIgnoredDiagnosticGroupTree(DiagGroupID id) const {
return state.isIgnoredDiagnosticGroupTree(id);
}
/// Whether the specified SourceFile enables a given diagnostic group
/// either syntactically, or via command-line flags.
bool isDiagnosticGroupEnabled(SourceFile *sf, DiagGroupID groupID) const;

void ignoreDiagnostic(DiagID id) {
state.compilerInternalIgnoreDiagnostic(id);
Expand Down Expand Up @@ -1366,7 +1378,8 @@ namespace swift {
Engine.TentativeDiagnostics.end());

for (auto &diagnostic : diagnostics) {
auto behavior = Engine.state.determineBehavior(diagnostic.Diag);
auto behavior = Engine.state.determineBehavior(diagnostic.Diag,
Engine.SourceMgr);
if (behavior == DiagnosticBehavior::Fatal ||
behavior == DiagnosticBehavior::Error)
return true;
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,13 @@ WARNING(attr_warn_unused_result_removed,none,
"'warn_unused_result' attribute behavior is now the default", ())
ERROR(attr_warn_unused_result_expected_rparen,none,
"expected ')' after 'warn_unused_result' attribute", ())

// warn
ERROR(attr_warn_expected_diagnostic_group_identifier,none,
"expected '%0' option to be a diagnostic group identifier", (StringRef))

ERROR(attr_warn_expected_known_behavior,none,
"expected diagnostic behavior argument '%0' to be either 'error', 'warning' or 'ignored'", (StringRef))

// _specialize
ERROR(attr_specialize_missing_colon,none,
Expand Down
4 changes: 2 additions & 2 deletions include/swift/Basic/DiagnosticOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
#define SWIFT_BASIC_DIAGNOSTICOPTIONS_H

#include "swift/Basic/PrintDiagnosticNamesMode.h"
#include "swift/Basic/WarningAsErrorRule.h"
#include "swift/Basic/WarningGroupBehaviorRule.h"
#include "llvm/ADT/Hashing.h"
#include <vector>

Expand Down Expand Up @@ -76,7 +76,7 @@ class DiagnosticOptions {
bool SuppressRemarks = false;

/// Rules for escalating warnings to errors
std::vector<WarningAsErrorRule> WarningsAsErrorsRules;
llvm::SmallVector<WarningGroupBehaviorRule, 4> WarningGroupControlRules;

/// When printing diagnostics, include either the diagnostic name
/// (diag::whatever) at the end or the associated diagnostic group.
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,9 @@ EXPERIMENTAL_FEATURE(AnyAppleOSAvailability, true)
/// Check @_implementationOnly imports in non-library-evolution mode.
EXPERIMENTAL_FEATURE(CheckImplementationOnly, true)

/// Enable source-level warning control with `@warn`
EXPERIMENTAL_FEATURE(SourceWarningControl, true)

#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
Expand Down
2 changes: 1 addition & 1 deletion include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ namespace swift {
/// Whether or not to allow experimental features that are only available
/// in "production".
#ifdef NDEBUG
bool RestrictNonProductionExperimentalFeatures = true;
bool RestrictNonProductionExperimentalFeatures = false;
#else
bool RestrictNonProductionExperimentalFeatures = false;
#endif
Expand Down
Loading