Skip to content

Commit 0b2c160

Browse files
authored
Merge pull request #80070 from gottesmm/swift-settings-only-once
[swift-settings] Only allow for a setting to be passed exactly once to #SwiftSettings.
2 parents 145a7c5 + 4b31382 commit 0b2c160

File tree

4 files changed

+71
-4
lines changed

4 files changed

+71
-4
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8399,5 +8399,10 @@ ERROR(swift_settings_invalid_setting, none,
83998399
ERROR(swift_settings_must_be_top_level, none,
84008400
"#SwiftSettings can only be invoked as a top level declaration", ())
84018401

8402+
ERROR(swift_settings_duplicate_setting, none,
8403+
"duplicate setting passed to #SwiftSettings", ())
8404+
NOTE(swift_settings_duplicate_setting_original_loc, none,
8405+
"setting originally passed here", ())
8406+
84028407
#define UNDEFINE_DIAGNOSTIC_MACROS
84038408
#include "DefineDiagnosticMacros.h"

lib/AST/Module.cpp

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
#include "llvm/ADT/SmallPtrSet.h"
6262
#include "llvm/ADT/StringExtras.h"
6363
#include "llvm/ADT/TinyPtrVector.h"
64+
#include "llvm/Support/CommandLine.h"
6465
#include "llvm/Support/MD5.h"
6566
#include "llvm/Support/MemoryBuffer.h"
6667
#include "llvm/Support/Path.h"
@@ -4195,20 +4196,41 @@ version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
41954196
// MARK: SwiftSettings
41964197
//===----------------------------------------------------------------------===//
41974198

4199+
static llvm::cl::opt<bool> AllowForDuplicateSwiftSettings(
4200+
"swift-settings-allow-duplicates",
4201+
llvm::cl::desc("Option that allows for duplicate SwiftSettings. Just for "
4202+
"compiler testing"),
4203+
llvm::cl::Hidden);
4204+
41984205
namespace {
41994206

42004207
enum class SwiftSettingKind {
42014208
Unknown = 0,
42024209
DefaultIsolation,
4210+
4211+
LastKind = DefaultIsolation,
42034212
};
42044213

42054214
struct SwiftSettingsWalker : ASTWalker {
42064215
SourceFile &sf;
42074216
ASTContext &ctx;
42084217
SourceFileLangOptions result;
42094218

4219+
SmallVector<Expr *, 1> swiftSettingIndexToOriginalExprMap;
4220+
42104221
SwiftSettingsWalker(SourceFile &sf, ASTContext &ctx)
4211-
: sf(sf), ctx(ctx), result() {}
4222+
: sf(sf), ctx(ctx), result() {
4223+
// NOTE: We do not store a value for Unknown.
4224+
for (unsigned i : range(unsigned(SwiftSettingKind::LastKind))) {
4225+
(void)i;
4226+
swiftSettingIndexToOriginalExprMap.push_back(nullptr);
4227+
}
4228+
}
4229+
4230+
Expr *&getOriginalSwiftSetting(SwiftSettingKind kind) {
4231+
assert(kind != SwiftSettingKind::Unknown);
4232+
return swiftSettingIndexToOriginalExprMap[unsigned(kind) - 1];
4233+
}
42124234

42134235
/// Given a specific CallExpr, pattern matches the CallExpr's first argument
42144236
/// to validate it is MainActor.self. Returns CanType() if the CallExpr has
@@ -4267,13 +4289,30 @@ struct SwiftSettingsWalker : ASTWalker {
42674289
continue;
42684290

42694291
case SwiftSettingKind::DefaultIsolation:
4292+
auto *&expr =
4293+
getOriginalSwiftSetting(SwiftSettingKind::DefaultIsolation);
4294+
4295+
// If we already have an expr, emit an error and continue.
4296+
if (!AllowForDuplicateSwiftSettings && expr) {
4297+
ctx.Diags.diagnose(arg.getStartLoc(),
4298+
diag::swift_settings_duplicate_setting);
4299+
ctx.Diags.diagnose(
4300+
expr->getLoc(),
4301+
diag::swift_settings_duplicate_setting_original_loc);
4302+
foundValidArg = true;
4303+
continue;
4304+
}
4305+
4306+
// Otherwise, set things up appropriately.
42704307
if (auto actor = patternMatchDefaultIsolationMainActor(callExpr)) {
4308+
expr = callExpr;
42714309
result.defaultIsolation = actor;
42724310
foundValidArg = true;
42734311
continue;
42744312
}
42754313

42764314
if (isa<NilLiteralExpr>(callExpr->getArgs()->getExpr(0))) {
4315+
expr = callExpr;
42774316
result.defaultIsolation = {Type()};
42784317
foundValidArg = true;
42794318
continue;
@@ -4344,7 +4383,7 @@ SwiftSettingsWalker::getSwiftSettingArgDecl(Argument arg) {
43444383
return {};
43454384

43464385
// Now lookup our swiftSettingDecl.
4347-
NominalTypeDecl *swiftSettingsDecl;
4386+
NominalTypeDecl *swiftSettingsDecl = nullptr;
43484387
{
43494388
SmallVector<ValueDecl *, 1> decls;
43504389
ctx.lookupInSwiftModule("SwiftSetting", decls);

test/Sema/swiftsettings.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -enable-experimental-feature SwiftSettings -enable-experimental-feature Macros -c -swift-version 6 -disable-availability-checking -verify %s
1+
// RUN: %target-swift-frontend -enable-experimental-feature SwiftSettings -enable-experimental-feature Macros -c -swift-version 6 -disable-availability-checking -verify -Xllvm -swift-settings-allow-duplicates %s
22

33
// REQUIRES: asserts
44
// REQUIRES: concurrency
@@ -15,7 +15,6 @@ actor MyActor {}
1515
#SwiftSettings(2) // expected-error {{Unrecognized setting passed to #SwiftSettings}}
1616
// expected-error @-1 {{cannot convert value of type 'Int' to expected argument type 'SwiftSetting'}}
1717

18-
// We should for now just take the last one that is specified.
1918
#SwiftSettings(.defaultIsolation(MainActor.self),
2019
.defaultIsolation(nil))
2120

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-swift-frontend -enable-experimental-feature SwiftSettings -enable-experimental-feature Macros -c -swift-version 6 -disable-availability-checking -verify %s
2+
3+
// REQUIRES: asserts
4+
// REQUIRES: concurrency
5+
// REQUIRES: swift_feature_Macros
6+
// REQUIRES: swift_feature_SwiftSettings
7+
8+
// This test specifically tests the behavior of #SwiftSettings when we find
9+
// multiple instances of the same setting.
10+
11+
actor MyActor {}
12+
13+
#SwiftSettings(.defaultIsolation(MainActor.self), // expected-note 6 {{setting originally passed here}}
14+
.defaultIsolation(nil)) // expected-error {{duplicate setting passed to #SwiftSettings}}
15+
#SwiftSettings(.defaultIsolation(nil)) // expected-error {{duplicate setting passed to #SwiftSettings}}
16+
#SwiftSettings(.defaultIsolation(MyActor.self)) // expected-error {{duplicate setting passed to #SwiftSettings}}
17+
#SwiftSettings(.defaultIsolation(1)) // expected-error {{duplicate setting passed to #SwiftSettings}}
18+
// expected-error @-1 {{cannot convert value of type 'Int' to expected argument type 'any Actor.Type'}}
19+
#SwiftSettings(2) // expected-error {{Unrecognized setting passed to #SwiftSettings}}
20+
// expected-error @-1 {{cannot convert value of type 'Int' to expected argument type 'SwiftSetting'}}
21+
22+
#SwiftSettings(.defaultIsolation(MainActor.self), // expected-error {{duplicate setting passed to #SwiftSettings}}
23+
.defaultIsolation(nil)) // expected-error {{duplicate setting passed to #SwiftSettings}}
24+

0 commit comments

Comments
 (0)