Skip to content

Commit a68adb9

Browse files
authored
Merge pull request #72008 from rjmccall/isolated-any-feature-suppression
Allow declarations to opt in to suppressing `@isolated(any)` instead of suppressing the entire declaration
2 parents 6c798a2 + fc538f3 commit a68adb9

26 files changed

+505
-103
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,14 @@ BridgedAlignmentAttr_createParsed(BridgedASTContext cContext,
481481
BridgedSourceLoc cAtLoc,
482482
BridgedSourceRange cRange, size_t cValue);
483483

484+
SWIFT_NAME("BridgedAllowFeatureSuppressionAttr.createParsed(_:atLoc:range:features:)")
485+
BridgedAllowFeatureSuppressionAttr
486+
BridgedAllowFeatureSuppressionAttr_createParsed(
487+
BridgedASTContext cContext,
488+
BridgedSourceLoc cAtLoc,
489+
BridgedSourceRange cRange,
490+
BridgedArrayRef cFeatures);
491+
484492
SWIFT_NAME("BridgedCDeclAttr.createParsed(_:atLoc:range:name:)")
485493
BridgedCDeclAttr BridgedCDeclAttr_createParsed(BridgedASTContext cContext,
486494
BridgedSourceLoc cAtLoc,

include/swift/AST/Attr.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ class DeclAttribute : public AttributeBase {
191191
SWIFT_INLINE_BITFIELD(NonisolatedAttr, DeclAttribute, 1,
192192
isUnsafe : 1
193193
);
194+
195+
SWIFT_INLINE_BITFIELD_FULL(AllowFeatureSuppressionAttr, DeclAttribute, 32,
196+
: NumPadBits,
197+
NumFeatures : 32
198+
);
194199
} Bits;
195200
// clang-format on
196201

@@ -2636,6 +2641,32 @@ template <typename ATTR, bool AllowInvalid> struct ToAttributeKind {
26362641
}
26372642
};
26382643

2644+
/// The @_allowFeatureSuppression(Foo, Bar) attribute. The feature
2645+
/// names are intentionally not validated, and the attribute itself is
2646+
/// not printed when rendering a module interface.
2647+
class AllowFeatureSuppressionAttr final
2648+
: public DeclAttribute,
2649+
private llvm::TrailingObjects<AllowFeatureSuppressionAttr, Identifier> {
2650+
friend TrailingObjects;
2651+
2652+
/// Create an implicit @objc attribute with the given (optional) name.
2653+
AllowFeatureSuppressionAttr(SourceLoc atLoc, SourceRange range,
2654+
bool implicit, ArrayRef<Identifier> features);
2655+
public:
2656+
static AllowFeatureSuppressionAttr *create(ASTContext &ctx, SourceLoc atLoc,
2657+
SourceRange range, bool implicit,
2658+
ArrayRef<Identifier> features);
2659+
2660+
ArrayRef<Identifier> getSuppressedFeatures() const {
2661+
return {getTrailingObjects<Identifier>(),
2662+
Bits.AllowFeatureSuppressionAttr.NumFeatures};
2663+
}
2664+
2665+
static bool classof(const DeclAttribute *DA) {
2666+
return DA->getKind() == DeclAttrKind::AllowFeatureSuppression;
2667+
}
2668+
};
2669+
26392670
/// Attributes that may be applied to declarations.
26402671
class DeclAttributes {
26412672
/// Linked list of declaration attributes.

include/swift/AST/DeclAttr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
488488
DECL_ATTR(_distributedThunkTarget, DistributedThunkTarget,
489489
OnAbstractFunction | UserInaccessible | ABIStableToAdd | ABIBreakingToRemove | APIStableToAdd | APIStableToRemove,
490490
156)
491-
LAST_DECL_ATTR(DistributedThunkTarget)
491+
DECL_ATTR(_allowFeatureSuppression, AllowFeatureSuppression,
492+
OnAnyDecl | UserInaccessible | NotSerialized | ABIStableToAdd | APIStableToAdd | ABIStableToRemove | APIStableToRemove,
493+
157)
494+
LAST_DECL_ATTR(AllowFeatureSuppression)
492495

493496
#undef DECL_ATTR_ALIAS
494497
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/DiagnosticEngine.h

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ namespace swift {
8888
};
8989
}
9090

91+
template <class... ArgTypes>
92+
using DiagArgTuple =
93+
std::tuple<typename detail::PassArgument<ArgTypes>::type...>;
94+
9195
/// A family of wrapper types for compiler data types that forces its
9296
/// underlying data to be formatted with full qualification.
9397
///
@@ -476,20 +480,28 @@ namespace swift {
476480
friend DiagnosticEngine;
477481
friend class InFlightDiagnostic;
478482

483+
Diagnostic(DiagID ID) : ID(ID) {}
484+
479485
public:
480486
// All constructors are intentionally implicit.
481487
template<typename ...ArgTypes>
482488
Diagnostic(Diag<ArgTypes...> ID,
483489
typename detail::PassArgument<ArgTypes>::type... VArgs)
484-
: ID(ID.ID) {
485-
DiagnosticArgument DiagArgs[] = {
486-
DiagnosticArgument(0), std::move(VArgs)...
487-
};
488-
Args.append(DiagArgs + 1, DiagArgs + 1 + sizeof...(VArgs));
490+
: Diagnostic(ID.ID) {
491+
Args.reserve(sizeof...(ArgTypes));
492+
gatherArgs(VArgs...);
489493
}
490494

491495
/*implicit*/Diagnostic(DiagID ID, ArrayRef<DiagnosticArgument> Args)
492496
: ID(ID), Args(Args.begin(), Args.end()) {}
497+
498+
template <class... ArgTypes>
499+
static Diagnostic fromTuple(Diag<ArgTypes...> id,
500+
const DiagArgTuple<ArgTypes...> &tuple) {
501+
Diagnostic result(id.ID);
502+
result.gatherArgsFromTuple<DiagArgTuple<ArgTypes...>, 0, ArgTypes...>(tuple);
503+
return result;
504+
}
493505

494506
// Accessors.
495507
DiagID getID() const { return ID; }
@@ -528,6 +540,37 @@ namespace swift {
528540

529541
void addChildNote(Diagnostic &&D);
530542
void insertChildNote(unsigned beforeIndex, Diagnostic &&D);
543+
544+
private:
545+
// gatherArgs could just be `Args.emplace_back(args)...;` if C++
546+
// allowed pack expansions in statement context.
547+
548+
// Base case.
549+
void gatherArgs() {}
550+
551+
// Pull one off the pack.
552+
template <class ArgType, class... RemainingArgTypes>
553+
void gatherArgs(ArgType arg, RemainingArgTypes... remainingArgs) {
554+
Args.emplace_back(arg);
555+
gatherArgs(remainingArgs...);
556+
}
557+
558+
// gatherArgsFromTuple could just be
559+
// `Args.emplace_back(std::get<packIndexOf<ArgTypes>>(tuple))...;`
560+
// in a better world.
561+
562+
// Base case.
563+
template <class Tuple, size_t Index>
564+
void gatherArgsFromTuple(const Tuple &tuple) {}
565+
566+
// Pull one off the pack.
567+
template <class Tuple, size_t Index,
568+
class ArgType, class... RemainingArgTypes>
569+
void gatherArgsFromTuple(const Tuple &tuple) {
570+
Args.emplace_back(std::move(std::get<Index>(tuple)));
571+
gatherArgsFromTuple<Tuple, Index + 1, RemainingArgTypes...>(
572+
std::move(tuple));
573+
}
531574
};
532575

533576
/// A diagnostic that has no input arguments, so it is trivially-destructable.
@@ -866,6 +909,73 @@ namespace swift {
866909
DiagnosticState &operator=(DiagnosticState &&) = default;
867910
};
868911

912+
/// A lightweight reference to a diagnostic that's been fully applied to
913+
/// its arguments. This allows a general routine (in the parser, say) to
914+
/// be customized to emit an arbitrary diagnostic without needing to
915+
/// eagerly construct a full Diagnostic. Like ArrayRef and function_ref,
916+
/// this stores a reference to what's likely to be a temporary, so it
917+
/// should only be used as a function parameter. If you need to persist
918+
/// the diagnostic, you'll have to call createDiagnostic().
919+
///
920+
/// You can initialize a DiagRef parameter in one of two ways:
921+
/// - passing a Diag<> as the argument, e.g.
922+
/// diag::circular_reference
923+
/// or
924+
/// - constructing it with a Diag and its arguments, e.g.
925+
/// {diag::circular_protocol_def, {proto->getName()}}
926+
///
927+
/// It'd be nice to let people write `{diag::my_error, arg0, arg1}`
928+
/// instead of `{diag::my_error, {arg0, arg1}}`, but we can't: the
929+
/// temporary needs to be created in the calling context.
930+
class DiagRef {
931+
DiagID id;
932+
933+
/// If this is null, then id is a Diag<> and there are no arguments.
934+
Diagnostic (*createFn)(DiagID id, const void *opaqueStorage);
935+
const void *opaqueStorage;
936+
937+
public:
938+
/// Construct a diagnostic from a diagnostic ID that's known to not take
939+
/// arguments.
940+
DiagRef(Diag<> id)
941+
: id(id.ID), createFn(nullptr), opaqueStorage(nullptr) {}
942+
943+
/// Construct a diagnostic from a diagnostic ID and its arguments.
944+
template <class... ArgTypes>
945+
DiagRef(Diag<ArgTypes...> id, const DiagArgTuple<ArgTypes...> &tuple)
946+
: id(id.ID),
947+
createFn(&createFromTuple<ArgTypes...>),
948+
opaqueStorage(&tuple) {}
949+
950+
// A specialization of the general constructor above for diagnostics
951+
// with no arguments; this is a useful optimization when a DiagRef
952+
// is constructed generically.
953+
DiagRef(Diag<> id, const DiagArgTuple<> &tuple)
954+
: DiagRef(id) {}
955+
956+
/// Return the diagnostic ID that this will emit.
957+
DiagID getID() const {
958+
return id;
959+
}
960+
961+
/// Create a full Diagnostic. It's safe to do this multiple times on
962+
/// a single DiagRef.
963+
Diagnostic createDiagnostic() {
964+
if (!createFn) {
965+
return Diagnostic(Diag<> {id});
966+
} else {
967+
return createFn(id, opaqueStorage);
968+
}
969+
}
970+
971+
private:
972+
template <class... ArgTypes>
973+
static Diagnostic createFromTuple(DiagID id, const void *opaqueStorage) {
974+
auto tuple = static_cast<const DiagArgTuple<ArgTypes...> *>(opaqueStorage);
975+
return Diagnostic::fromTuple(Diag<ArgTypes...> {id}, *tuple);
976+
}
977+
};
978+
869979
/// Class responsible for formatting diagnostics and presenting them
870980
/// to the user.
871981
class DiagnosticEngine {
@@ -1113,6 +1223,12 @@ namespace swift {
11131223
return diagnose(Loc, Diagnostic(ID, std::move(Args)...));
11141224
}
11151225

1226+
/// Emit the given lazily-applied diagnostic at the specified
1227+
/// source location.
1228+
InFlightDiagnostic diagnose(SourceLoc loc, DiagRef diag) {
1229+
return diagnose(loc, diag.createDiagnostic());
1230+
}
1231+
11161232
/// Delete an API that may lead clients to avoid specifying source location.
11171233
template<typename ...ArgTypes>
11181234
InFlightDiagnostic

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,10 @@ ERROR(attr_rawlayout_expected_params,none,
18891889

18901890
ERROR(attr_extern_expected_label,none,
18911891
"expected %0 argument to @_extern attribute", (StringRef))
1892+
1893+
ERROR(attr_expected_feature_name,none,
1894+
"expected feature name in @%0 attribute", (StringRef))
1895+
18921896
//------------------------------------------------------------------------------
18931897
// MARK: Generics parsing diagnostics
18941898
//------------------------------------------------------------------------------

include/swift/AST/PrintOptions.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,10 +376,14 @@ struct PrintOptions {
376376
/// `AsyncIteratorProtocol` for backward-compatibility reasons.
377377
bool AsyncSequenceRethrows = false;
378378

379+
/// Suppress the @isolated(any) attribute.
380+
bool SuppressIsolatedAny = false;
381+
379382
/// List of attribute kinds that should not be printed.
380383
std::vector<AnyAttrKind> ExcludeAttrList = {
381384
DeclAttrKind::Transparent, DeclAttrKind::Effects,
382-
DeclAttrKind::FixedLayout, DeclAttrKind::ShowInInterface};
385+
DeclAttrKind::FixedLayout, DeclAttrKind::ShowInInterface,
386+
};
383387

384388
/// List of attribute kinds that should be printed exclusively.
385389
/// Empty means allow all.

include/swift/Basic/Feature.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ constexpr unsigned numFeatures() {
3535
return NumFeatures;
3636
}
3737

38-
/// Determine whether the given feature is suppressible.
39-
bool isSuppressibleFeature(Feature feature);
40-
4138
/// Check whether the given feature is available in production compilers.
4239
bool isFeatureAvailableInProduction(Feature feature);
4340

include/swift/Basic/Features.def

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
// imply the existence of earlier features. (This only needs to apply to
3535
// suppressible features.)
3636
//
37+
// If suppressing a feature in general is problematic, but it's okay to
38+
// suppress it for specific declarations, the feature can be made
39+
// conditionally suppressible. Declarations opt in to suppression with
40+
// the @_allowFeatureSuppression attribute.
41+
//
3742
// BASELINE_LANGUAGE_FEATURE is the same as LANGUAGE_FEATURE, but is used
3843
// for features that can be assumed to be available in any Swift compiler that
3944
// will be used to process the textual interface files produced by this
@@ -44,11 +49,46 @@
4449
# error define LANGUAGE_FEATURE before including Features.def
4550
#endif
4651

52+
// A feature that's both suppressible and experimental.
53+
// Delegates to whichever the includer defines.
54+
#ifndef SUPPRESSIBLE_EXPERIMENTAL_FEATURE
55+
# if defined(SUPPRESSIBLE_LANGUAGE_FEATURE) && \
56+
defined(EXPERIMENTAL_FEATURE)
57+
# error ambiguous defines when including Features.def
58+
# elif defined(SUPPRESSIBLE_LANGUAGE_FEATURE)
59+
# define SUPPRESSIBLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
60+
SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, 0, #FeatureName)
61+
# else
62+
# define SUPPRESSIBLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
63+
EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
64+
# endif
65+
#endif
66+
4767
#ifndef SUPPRESSIBLE_LANGUAGE_FEATURE
48-
#define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
68+
# define SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
4969
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
5070
#endif
5171

72+
// A feature that's both conditionally-suppressible and experimental.
73+
// Delegates to whichever the includer defines.
74+
#ifndef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
75+
# if defined(CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE) && \
76+
defined(EXPERIMENTAL_FEATURE)
77+
# error ambiguous defines when including Features.def
78+
# elif defined(CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE)
79+
# define CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
80+
CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, 0, #FeatureName)
81+
# else
82+
# define CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
83+
EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
84+
# endif
85+
#endif
86+
87+
#ifndef CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE
88+
# define CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
89+
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
90+
#endif
91+
5292
#ifndef UPCOMING_FEATURE
5393
# define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
5494
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
@@ -295,11 +335,14 @@ EXPERIMENTAL_FEATURE(DynamicActorIsolation, false)
295335
EXPERIMENTAL_FEATURE(BorrowingSwitch, true)
296336

297337
// Enable isolated(any) attribute on function types.
298-
EXPERIMENTAL_FEATURE(IsolatedAny, true)
338+
CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE(IsolatedAny, true)
299339

300340
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
301341
#undef EXPERIMENTAL_FEATURE
302342
#undef UPCOMING_FEATURE
303343
#undef BASELINE_LANGUAGE_FEATURE
344+
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
345+
#undef CONDITIONALLY_SUPPRESSIBLE_LANGUAGE_FEATURE
346+
#undef SUPPRESSIBLE_EXPERIMENTAL_FEATURE
304347
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
305348
#undef LANGUAGE_FEATURE

0 commit comments

Comments
 (0)