Skip to content

Commit 2f5cb80

Browse files
authored
Merge pull request #36865 from beccadax/remarkable-notes
2 parents 3c19cc4 + d4cae43 commit 2f5cb80

26 files changed

+1230
-733
lines changed

include/swift/AST/Attr.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,7 @@ class ObjCAttr final : public DeclAttribute,
854854
/// Determine whether the name associated with this attribute was
855855
/// implicit.
856856
bool isNameImplicit() const { return Bits.ObjCAttr.ImplicitName; }
857+
void setNameImplicit(bool newValue) { Bits.ObjCAttr.ImplicitName = newValue; }
857858

858859
/// Set the name of this entity.
859860
void setName(ObjCSelector name, bool implicit) {
@@ -882,11 +883,6 @@ class ObjCAttr final : public DeclAttribute,
882883
Bits.ObjCAttr.Swift3Inferred = inferred;
883884
}
884885

885-
/// Clear the name of this entity.
886-
void clearName() {
887-
NameData = nullptr;
888-
}
889-
890886
/// Retrieve the source locations for the names in a non-implicit
891887
/// nullary or selector attribute.
892888
ArrayRef<SourceLoc> getNameLocs() const;

include/swift/AST/DiagnosticEngine.h

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ namespace swift {
115115
VersionTuple,
116116
LayoutConstraint,
117117
ActorIsolation,
118+
Diagnostic
118119
};
119120

120121
namespace diag {
@@ -146,6 +147,7 @@ namespace swift {
146147
llvm::VersionTuple VersionVal;
147148
LayoutConstraint LayoutConstraintVal;
148149
ActorIsolation ActorIsolationVal;
150+
DiagnosticInfo *DiagnosticVal;
149151
};
150152

151153
public:
@@ -243,6 +245,11 @@ namespace swift {
243245
ActorIsolationVal(AI) {
244246
}
245247

248+
DiagnosticArgument(DiagnosticInfo *D)
249+
: Kind(DiagnosticArgumentKind::Diagnostic),
250+
DiagnosticVal(D) {
251+
}
252+
246253
/// Initializes a diagnostic argument using the underlying type of the
247254
/// given enum.
248255
template<
@@ -343,6 +350,11 @@ namespace swift {
343350
assert(Kind == DiagnosticArgumentKind::ActorIsolation);
344351
return ActorIsolationVal;
345352
}
353+
354+
DiagnosticInfo *getAsDiagnostic() const {
355+
assert(Kind == DiagnosticArgumentKind::Diagnostic);
356+
return DiagnosticVal;
357+
}
346358
};
347359

348360
/// Describes the current behavior to take with a diagnostic.
@@ -410,6 +422,7 @@ namespace swift {
410422
DiagnosticBehavior BehaviorLimit = DiagnosticBehavior::Unspecified;
411423

412424
friend DiagnosticEngine;
425+
friend class InFlightDiagnostic;
413426

414427
public:
415428
// All constructors are intentionally implicit.
@@ -515,6 +528,42 @@ namespace swift {
515528
/// emitted as a warning, but a note will still be emitted as a note.
516529
InFlightDiagnostic &limitBehavior(DiagnosticBehavior limit);
517530

531+
/// Wraps this diagnostic in another diagnostic. That is, \p wrapper will be
532+
/// emitted in place of the diagnostic that otherwise would have been
533+
/// emitted.
534+
///
535+
/// The first argument of \p wrapper must be of type 'Diagnostic *'.
536+
///
537+
/// The emitted diagnostic will have:
538+
///
539+
/// \li The ID, message, and behavior of \c wrapper.
540+
/// \li The arguments of \c wrapper, with the last argument replaced by the
541+
/// diagnostic currently in \c *this.
542+
/// \li The location, ranges, decl, fix-its, and behavior limit of the
543+
/// diagnostic currently in \c *this.
544+
InFlightDiagnostic &wrapIn(const Diagnostic &wrapper);
545+
546+
/// Wraps this diagnostic in another diagnostic. That is, \p ID and
547+
/// \p VArgs will be emitted in place of the diagnostic that otherwise would
548+
/// have been emitted.
549+
///
550+
/// The first argument of \p ID must be of type 'Diagnostic *'.
551+
///
552+
/// The emitted diagnostic will have:
553+
///
554+
/// \li The ID, message, and behavior of \c ID.
555+
/// \li The arguments of \c VArgs, with an argument appended for the
556+
/// diagnostic currently in \c *this.
557+
/// \li The location, ranges, decl, fix-its, and behavior limit of the
558+
/// diagnostic currently in \c *this.
559+
template<typename ...ArgTypes>
560+
InFlightDiagnostic &
561+
wrapIn(Diag<DiagnosticInfo *, ArgTypes...> ID,
562+
typename detail::PassArgument<ArgTypes>::type... VArgs) {
563+
Diagnostic wrapper{ID, nullptr, std::move(VArgs)...};
564+
return wrapIn(wrapper);
565+
}
566+
518567
/// Add a token-based range to the currently-active diagnostic.
519568
InFlightDiagnostic &highlight(SourceRange R);
520569

@@ -678,6 +727,16 @@ namespace swift {
678727
ignoredDiagnostics[(unsigned)id] = ignored;
679728
}
680729

730+
void swap(DiagnosticState &other) {
731+
std::swap(showDiagnosticsAfterFatalError, other.showDiagnosticsAfterFatalError);
732+
std::swap(suppressWarnings, other.suppressWarnings);
733+
std::swap(warningsAsErrors, other.warningsAsErrors);
734+
std::swap(fatalErrorOccurred, other.fatalErrorOccurred);
735+
std::swap(anyErrorOccurred, other.anyErrorOccurred);
736+
std::swap(previousBehavior, other.previousBehavior);
737+
std::swap(ignoredDiagnostics, other.ignoredDiagnostics);
738+
}
739+
681740
private:
682741
// Make the state movable only
683742
DiagnosticState(const DiagnosticState &) = delete;
@@ -706,6 +765,10 @@ namespace swift {
706765
/// The currently active diagnostic, if there is one.
707766
Optional<Diagnostic> ActiveDiagnostic;
708767

768+
/// Diagnostics wrapped by ActiveDiagnostic, if any.
769+
SmallVector<DiagnosticInfo, 2> WrappedDiagnostics;
770+
SmallVector<std::vector<DiagnosticArgument>, 4> WrappedDiagnosticArgs;
771+
709772
/// All diagnostics that have are no longer active but have not yet
710773
/// been emitted due to an open transaction.
711774
SmallVector<Diagnostic, 4> TentativeDiagnostics;

include/swift/AST/DiagnosticsSema.def

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5018,10 +5018,11 @@ NOTE(objc_declared_here,none,
50185018
OBJC_DIAG_SELECT " declared here",
50195019
(unsigned, DeclName))
50205020

5021+
// %2 and %3 are unused to make signature match with diag::objc_redecl.
50215022
ERROR(objc_redecl_same,none,
5022-
OBJC_DIAG_SELECT " with Objective-C selector %2 conflicts with "
5023+
OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with "
50235024
"previous declaration with the same Objective-C selector",
5024-
(unsigned, DeclName, ObjCSelector))
5025+
(unsigned, DeclName, unsigned, DeclName, ObjCSelector))
50255026

50265027
ERROR(objc_override_other,none,
50275028
OBJC_DIAG_SELECT " with Objective-C selector %4 conflicts with "
@@ -5852,31 +5853,43 @@ ERROR(atomics_ordering_must_be_constant, none,
58525853
// MARK: access notes
58535854
//------------------------------------------------------------------------------
58545855

5856+
#define WHICH_ACCESS_NOTE(reason) "specified by access note for %" #reason
5857+
58555858
REMARK(attr_added_by_access_note, none,
5856-
"access note for %0 adds %select{attribute|modifier}1 '%2' to this %3",
5857-
(StringRef, bool, StringRef, DescriptiveDeclKind))
5859+
"implicitly added '%1' to this %2, as " WHICH_ACCESS_NOTE(0),
5860+
(StringRef, StringRef, DescriptiveDeclKind))
58585861
NOTE(fixit_attr_added_by_access_note, none,
5859-
"add %select{attribute|modifier}0 explicitly to silence this warning",
5860-
(bool))
5862+
"add '%0' explicitly to silence this warning",
5863+
(StringRef))
58615864

58625865
REMARK(attr_removed_by_access_note, none,
5863-
"access note for %0 removes %select{attribute|modifier}1 '%2' from "
5864-
"this %3",
5865-
(StringRef, bool, StringRef, DescriptiveDeclKind))
5866+
"implicitly removed '%1' from this %3, as " WHICH_ACCESS_NOTE(0),
5867+
(StringRef, StringRef, DescriptiveDeclKind))
58665868
NOTE(fixit_attr_removed_by_access_note, none,
5867-
"remove %select{attribute|modifier}0 explicitly to silence this warning",
5868-
(bool))
5869+
"remove '%0' explicitly to silence this warning",
5870+
(StringRef))
58695871

58705872
REMARK(attr_objc_name_changed_by_access_note, none,
5871-
"access note for %0 changes the '@objc' name of this %1 to %2",
5872-
(StringRef, DescriptiveDeclKind, ObjCSelector))
5873+
"implicitly changed Objective-C name of this %1 to %2, as "
5874+
WHICH_ACCESS_NOTE(0),
5875+
(StringRef, DescriptiveDeclKind, ObjCSelector))
58735876
NOTE(fixit_attr_objc_name_changed_by_access_note, none,
5874-
"change '@objc' name in source code explicitly to silence this warning",
5877+
"change Objective-C name explicitly to silence this warning",
58755878
())
5876-
REMARK(attr_objc_name_conflicts_with_access_note, none,
5877-
"access note for %0 changes the '@objc' name of this %1 to %2, but "
5878-
"source code specifies %3; the access note will be ignored",
5879-
(StringRef, DescriptiveDeclKind, ObjCSelector, ObjCSelector))
5879+
5880+
// Bad access note diagnostics. These are usually emitted as remarks, but
5881+
// '-Raccess-note=all-validate' emits them as errors.
5882+
5883+
ERROR(attr_objc_name_conflicts_with_access_note, none,
5884+
"ignored access note: did not change Objective-C name of this %1 from %2 "
5885+
"to %3, even though it was " WHICH_ACCESS_NOTE(0),
5886+
(StringRef, DescriptiveDeclKind, ObjCSelector, ObjCSelector))
5887+
ERROR(wrap_invalid_attr_added_by_access_note, none,
5888+
"ignored access note: %0; did not implicitly add '%2' to this %3, even "
5889+
"though it was " WHICH_ACCESS_NOTE(1),
5890+
(DiagnosticInfo *, StringRef, StringRef, DescriptiveDeclKind))
5891+
5892+
#undef WHICH_ACCESS_NOTE
58805893

58815894
#define UNDEFINE_DIAGNOSTIC_MACROS
58825895
#include "DefineDiagnosticMacros.h"

include/swift/AST/SourceFile.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,18 @@ class SourceFile final : public FileUnit {
241241
/// unsatisfied, which might conflict with other Objective-C methods.
242242
std::vector<ObjCUnsatisfiedOptReq> ObjCUnsatisfiedOptReqs;
243243

244+
/// A selector that is used by two different declarations in the same class.
245+
/// Fields: classDecl, selector, isInstanceMethod.
244246
using ObjCMethodConflict = std::tuple<ClassDecl *, ObjCSelector, bool>;
245247

246248
/// List of Objective-C member conflicts we have found during type checking.
247249
std::vector<ObjCMethodConflict> ObjCMethodConflicts;
248250

251+
/// List of attributes added by access notes, used to emit remarks for valid
252+
/// ones.
253+
llvm::DenseMap<ValueDecl *, std::vector<DeclAttribute *>>
254+
AttrsAddedByAccessNotes;
255+
249256
/// Describes what kind of file this is, which can affect some type checking
250257
/// and other behavior.
251258
const SourceFileKind Kind;

include/swift/Basic/LangOptions.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
namespace swift {
3838

39+
enum class DiagnosticBehavior : uint8_t;
40+
3941
/// Kind of implicit platform conditions.
4042
enum class PlatformConditionKind {
4143
#define PLATFORM_CONDITION(LABEL, IDENTIFIER) LABEL,
@@ -69,6 +71,13 @@ namespace swift {
6971
Other
7072
};
7173

74+
enum class AccessNoteDiagnosticBehavior : uint8_t {
75+
Ignore,
76+
RemarkOnFailure,
77+
RemarkOnFailureOrSuccess,
78+
ErrorOnFailureRemarkOnSuccess
79+
};
80+
7281
/// A collection of options that affect the language dialect and
7382
/// provide compiler debugging facilities.
7483
class LangOptions final {
@@ -339,6 +348,17 @@ namespace swift {
339348
std::shared_ptr<llvm::Regex> OptimizationRemarkPassedPattern;
340349
std::shared_ptr<llvm::Regex> OptimizationRemarkMissedPattern;
341350

351+
/// How should we emit diagnostics about access notes?
352+
AccessNoteDiagnosticBehavior AccessNoteBehavior =
353+
AccessNoteDiagnosticBehavior::RemarkOnFailureOrSuccess;
354+
355+
DiagnosticBehavior getAccessNoteFailureLimit() const;
356+
357+
bool shouldRemarkOnAccessNoteSuccess() const {
358+
return AccessNoteBehavior >=
359+
AccessNoteDiagnosticBehavior::RemarkOnFailureOrSuccess;
360+
}
361+
342362
/// Whether collect tokens during parsing for syntax coloring.
343363
bool CollectParsedToken = false;
344364

include/swift/Option/FrontendOptions.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,12 @@ def enable_infer_public_concurrent_value : Flag<["-"], "enable-infer-public-send
196196
def disable_infer_public_concurrent_value : Flag<["-"], "disable-infer-public-sendable">,
197197
HelpText<"Disable inference of Sendable conformances for public structs and enums">;
198198

199+
def Raccess_note : Separate<["-"], "Raccess-note">,
200+
MetaVarName<"none|failures|all|all-validate">,
201+
HelpText<"Control access note remarks (default: all)">;
202+
def Raccess_note_EQ : Joined<["-"], "Raccess-note=">,
203+
Alias<Raccess_note>;
204+
199205
} // end let Flags = [FrontendOption, NoDriverOption]
200206

201207
def debug_crash_Group : OptionGroup<"<automatic crashing options>">;

lib/AST/DiagnosticEngine.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,38 @@ InFlightDiagnostic::limitBehavior(DiagnosticBehavior limit) {
319319
return *this;
320320
}
321321

322+
InFlightDiagnostic &
323+
InFlightDiagnostic::wrapIn(const Diagnostic &wrapper) {
324+
// Save current active diagnostic into WrappedDiagnostics, ignoring state
325+
// so we don't get a None return or influence future diagnostics.
326+
DiagnosticState tempState;
327+
Engine->state.swap(tempState);
328+
llvm::SaveAndRestore<DiagnosticBehavior>
329+
limit(Engine->getActiveDiagnostic().BehaviorLimit,
330+
DiagnosticBehavior::Unspecified);
331+
332+
Engine->WrappedDiagnostics.push_back(
333+
*Engine->diagnosticInfoForDiagnostic(Engine->getActiveDiagnostic()));
334+
335+
Engine->state.swap(tempState);
336+
337+
auto &wrapped = Engine->WrappedDiagnostics.back();
338+
339+
// Copy and update its arg list.
340+
Engine->WrappedDiagnosticArgs.emplace_back(wrapped.FormatArgs);
341+
wrapped.FormatArgs = Engine->WrappedDiagnosticArgs.back();
342+
343+
// Overwrite the ID and argument with those from the wrapper.
344+
Engine->getActiveDiagnostic().ID = wrapper.ID;
345+
Engine->getActiveDiagnostic().Args = wrapper.Args;
346+
347+
// Set the argument to the diagnostic being wrapped.
348+
assert(wrapper.getArgs().front().getKind() == DiagnosticArgumentKind::Diagnostic);
349+
Engine->getActiveDiagnostic().Args.front() = &wrapped;
350+
351+
return *this;
352+
}
353+
322354
void InFlightDiagnostic::flush() {
323355
if (!IsActive)
324356
return;
@@ -525,7 +557,7 @@ static bool isMainActor(Type type) {
525557

526558
/// Format a single diagnostic argument and write it to the given
527559
/// stream.
528-
static void formatDiagnosticArgument(StringRef Modifier,
560+
static void formatDiagnosticArgument(StringRef Modifier,
529561
StringRef ModifierArguments,
530562
ArrayRef<DiagnosticArgument> Args,
531563
unsigned ArgIndex,
@@ -752,6 +784,7 @@ static void formatDiagnosticArgument(StringRef Modifier,
752784
<< FormatOpts.ClosingQuotationMark;
753785
break;
754786
case DiagnosticArgumentKind::ActorIsolation:
787+
assert(Modifier.empty() && "Improper modifier for ActorIsolation argument");
755788
switch (auto isolation = Arg.getAsActorIsolation()) {
756789
case ActorIsolation::ActorInstance:
757790
Out << "actor-isolated";
@@ -775,6 +808,15 @@ static void formatDiagnosticArgument(StringRef Modifier,
775808
Out << "nonisolated";
776809
break;
777810
}
811+
break;
812+
813+
case DiagnosticArgumentKind::Diagnostic: {
814+
assert(Modifier.empty() && "Improper modifier for Diagnostic argument");
815+
auto diagArg = Arg.getAsDiagnostic();
816+
DiagnosticEngine::formatDiagnosticText(Out, diagArg->FormatString,
817+
diagArg->FormatArgs);
818+
break;
819+
}
778820
}
779821
}
780822

@@ -953,6 +995,8 @@ void DiagnosticEngine::flushActiveDiagnostic() {
953995
assert(ActiveDiagnostic && "No active diagnostic to flush");
954996
if (TransactionCount == 0) {
955997
emitDiagnostic(*ActiveDiagnostic);
998+
WrappedDiagnostics.clear();
999+
WrappedDiagnosticArgs.clear();
9561000
} else {
9571001
onTentativeDiagnosticFlush(*ActiveDiagnostic);
9581002
TentativeDiagnostics.emplace_back(std::move(*ActiveDiagnostic));
@@ -965,6 +1009,8 @@ void DiagnosticEngine::emitTentativeDiagnostics() {
9651009
emitDiagnostic(diag);
9661010
}
9671011
TentativeDiagnostics.clear();
1012+
WrappedDiagnostics.clear();
1013+
WrappedDiagnosticArgs.clear();
9681014
}
9691015

9701016
/// Returns the access level of the least accessible PrettyPrintedDeclarations

0 commit comments

Comments
 (0)