@@ -2012,6 +2012,9 @@ class MultiConformanceChecker {
2012
2012
// / Determine whether the given requirement was left unsatisfied.
2013
2013
bool isUnsatisfiedReq (NormalProtocolConformance *conformance, ValueDecl *req);
2014
2014
2015
+ // / Diagnose redundant `@preconcurrency` attributes on conformances.
2016
+ void diagnoseRedundantPreconcurrency ();
2017
+
2015
2018
public:
2016
2019
MultiConformanceChecker (ASTContext &ctx) : Context(ctx) {}
2017
2020
@@ -2089,6 +2092,67 @@ static void diagnoseProtocolStubFixit(
2089
2092
NormalProtocolConformance *conformance,
2090
2093
ArrayRef<ASTContext::MissingWitness> missingWitnesses);
2091
2094
2095
+ void MultiConformanceChecker::diagnoseRedundantPreconcurrency () {
2096
+ // Collect explicit preconcurrency conformances for which preconcurrency is
2097
+ // not directly effectful.
2098
+ SmallVector<NormalProtocolConformance *, 2 > explicitConformances;
2099
+ for (auto *conformance : AllConformances) {
2100
+ if (conformance->getSourceKind () == ConformanceEntryKind::Explicit &&
2101
+ conformance->isPreconcurrency () &&
2102
+ !conformance->isPreconcurrencyEffectful ()) {
2103
+ explicitConformances.push_back (conformance);
2104
+ }
2105
+ }
2106
+
2107
+ if (explicitConformances.empty ()) {
2108
+ return ;
2109
+ }
2110
+
2111
+ // If preconcurrency is effectful for an implied conformance (a conformance
2112
+ // to an inherited protocol), consider it effectful for the corresponding
2113
+ // explicit one.
2114
+ for (auto *conformance : AllConformances) {
2115
+ switch (conformance->getSourceKind ()) {
2116
+ case ConformanceEntryKind::Inherited:
2117
+ case ConformanceEntryKind::PreMacroExpansion:
2118
+ llvm_unreachable (" Invalid normal protocol conformance kind" );
2119
+ case ConformanceEntryKind::Explicit:
2120
+ case ConformanceEntryKind::Synthesized:
2121
+ continue ;
2122
+ case ConformanceEntryKind::Implied:
2123
+ if (!conformance->isPreconcurrency () ||
2124
+ !conformance->isPreconcurrencyEffectful ()) {
2125
+ continue ;
2126
+ }
2127
+
2128
+ auto *proto = conformance->getProtocol ();
2129
+ for (auto *explicitConformance : explicitConformances) {
2130
+ if (explicitConformance->getProtocol ()->inheritsFrom (proto)) {
2131
+ explicitConformance->setPreconcurrencyEffectful ();
2132
+ }
2133
+ }
2134
+
2135
+ continue ;
2136
+ }
2137
+ }
2138
+
2139
+ // Diagnose all explicit preconcurrency conformances for which preconcurrency
2140
+ // is not effectful (redundant).
2141
+ for (auto *conformance : explicitConformances) {
2142
+ if (!conformance->isPreconcurrencyEffectful ()) {
2143
+ auto diag = Context.Diags .diagnose (
2144
+ conformance->getLoc (), diag::preconcurrency_conformance_not_used,
2145
+ conformance->getProtocol ()->getDeclaredInterfaceType ());
2146
+
2147
+ SourceLoc preconcurrencyLoc = conformance->getPreconcurrencyLoc ();
2148
+ if (preconcurrencyLoc.isValid ()) {
2149
+ SourceLoc endLoc = preconcurrencyLoc.getAdvancedLoc (1 );
2150
+ diag.fixItRemove (SourceRange (preconcurrencyLoc, endLoc));
2151
+ }
2152
+ }
2153
+ }
2154
+ }
2155
+
2092
2156
void MultiConformanceChecker::checkAllConformances () {
2093
2157
if (AllConformances.empty ()) {
2094
2158
return ;
@@ -2158,6 +2222,9 @@ void MultiConformanceChecker::checkAllConformances() {
2158
2222
}
2159
2223
}
2160
2224
2225
+ // Diagnose any redundant preconcurrency.
2226
+ this ->diagnoseRedundantPreconcurrency ();
2227
+
2161
2228
// Emit diagnostics at the very end.
2162
2229
for (auto *conformance : AllConformances) {
2163
2230
emitDelayedDiags (conformance);
@@ -5353,16 +5420,8 @@ void ConformanceChecker::resolveValueWitnesses() {
5353
5420
}
5354
5421
}
5355
5422
5356
- if (Conformance->isPreconcurrency () && !usesPreconcurrency) {
5357
- auto diag = DC->getASTContext ().Diags .diagnose (
5358
- Conformance->getLoc (), diag::preconcurrency_conformance_not_used,
5359
- Proto->getDeclaredInterfaceType ());
5360
-
5361
- SourceLoc preconcurrencyLoc = Conformance->getPreconcurrencyLoc ();
5362
- if (preconcurrencyLoc.isValid ()) {
5363
- SourceLoc endLoc = preconcurrencyLoc.getAdvancedLoc (1 );
5364
- diag.fixItRemove (SourceRange (preconcurrencyLoc, endLoc));
5365
- }
5423
+ if (Conformance->isPreconcurrency () && usesPreconcurrency) {
5424
+ Conformance->setPreconcurrencyEffectful ();
5366
5425
}
5367
5426
5368
5427
// Finally, check some ad-hoc protocol requirements.
0 commit comments