Skip to content

Commit 358b507

Browse files
Merge pull request #5493 from swiftwasm/main
[pull] swiftwasm from main
2 parents 74c1a4a + 7c83991 commit 358b507

20 files changed

+534
-129
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4616,6 +4616,9 @@ ERROR(unknown_case_multiple_patterns,none,
46164616
ERROR(unknown_case_must_be_last,none,
46174617
"'@unknown' can only be applied to the last case in a switch", ())
46184618

4619+
WARNING(move_only_pattern_match_not_consumed,none,
4620+
"noncopyable binding being pattern-matched must have the 'consume' operator applied", ())
4621+
46194622
WARNING(where_on_one_item, none,
46204623
"'where' only applies to the second pattern match in this case", ())
46214624

include/swift/SIL/SILBuilder.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -413,18 +413,18 @@ class SILBuilder {
413413
AllocStackInst *createAllocStack(SILLocation Loc, SILType elementType,
414414
Optional<SILDebugVariable> Var = None,
415415
bool hasDynamicLifetime = false,
416-
bool isLexical = false, bool wasMoved = false
417-
#ifndef NDEBUG
418-
,
416+
bool isLexical = false,
417+
bool wasMoved = false,
419418
bool skipVarDeclAssert = false
420-
#endif
421419
) {
422420
llvm::SmallString<4> Name;
423421
Loc.markAsPrologue();
424422
#ifndef NDEBUG
425423
if (dyn_cast_or_null<VarDecl>(Loc.getAsASTNode<Decl>()))
426424
assert((skipVarDeclAssert || Loc.isSynthesizedAST() || Var) &&
427425
"location is a VarDecl, but SILDebugVariable is empty");
426+
#else
427+
(void)skipVarDeclAssert;
428428
#endif
429429
return insert(AllocStackInst::create(
430430
getSILDebugLocation(Loc, true), elementType, getFunction(),
@@ -473,19 +473,20 @@ class SILBuilder {
473473
return createAllocBox(loc, SILBoxType::get(fieldType.getASTType()), Var,
474474
hasDynamicLifetime, reflection,
475475
usesMoveableValueDebugInfo,
476-
/*skipVarDeclAssert*/ false, hasPointerEscape);
476+
/*skipVarDeclAssert*/ false,
477+
hasPointerEscape);
477478
}
478479

479480
AllocBoxInst *createAllocBox(SILLocation Loc, CanSILBoxType BoxType,
480481
Optional<SILDebugVariable> Var = None,
481482
bool hasDynamicLifetime = false,
482483
bool reflection = false,
483-
bool usesMoveableValueDebugInfo = false
484-
#ifndef NDEBUG
485-
,
484+
bool usesMoveableValueDebugInfo = false,
486485
bool skipVarDeclAssert = false,
487-
#endif
488486
bool hasPointerEscape = false) {
487+
#if NDEBUG
488+
(void)skipVarDeclAssert;
489+
#endif
489490
llvm::SmallString<4> Name;
490491
Loc.markAsPrologue();
491492
assert((skipVarDeclAssert ||

lib/AST/Module.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,13 @@ void SourceLookupCache::populateAuxiliaryDeclCache() {
403403
for (auto macroNames : introducedNames) {
404404
auto macroRef = macroNames.getFirst();
405405
for (auto name : macroNames.getSecond()) {
406+
407+
// If this macro isn't in a module-scope context, and the introduced
408+
// name isn't an operator, we shouldn't be able to see it.
409+
if (!decl->getDeclContext()->isModuleScopeContext() &&
410+
!name.getBaseName().isOperator())
411+
continue;
412+
406413
auto *placeholder = MissingDecl::forUnexpandedMacro(macroRef, decl);
407414
name.addToLookupTable(TopLevelAuxiliaryDecls, placeholder);
408415
}
@@ -485,6 +492,12 @@ void SourceLookupCache::lookupValue(DeclName Name, NLKind LookupKind,
485492
for (auto *unexpandedDecl : unexpandedDecls) {
486493
unexpandedDecl->forEachMacroExpandedDecl(
487494
[&](ValueDecl *decl) {
495+
// If the declaration is not a module-scope declaration, and
496+
// isn't an operator, ignore it.
497+
if (!decl->getDeclContext()->isModuleScopeContext() &&
498+
!decl->getName().getBaseName().isOperator())
499+
return;
500+
488501
if (decl->getName().matchesRef(Name)) {
489502
if (macroExpandedDecls.insert(decl).second)
490503
Result.push_back(decl);

lib/ClangImporter/ClangImporter.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5049,7 +5049,8 @@ DeclAttributes cloneImportedAttributes(ValueDecl *decl, ASTContext &context) {
50495049
return attrs;
50505050
}
50515051

5052-
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
5052+
static ValueDecl *
5053+
cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext) {
50535054
if (auto fn = dyn_cast<FuncDecl>(decl)) {
50545055
// TODO: function templates are specialized during type checking so to
50555056
// support these we need to tell Swift to type check the synthesized bodies.
@@ -6333,16 +6334,23 @@ Decl *ClangImporter::importDeclDirectly(const clang::NamedDecl *decl) {
63336334
return Impl.importDecl(decl, Impl.CurrentVersion);
63346335
}
63356336

6336-
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
6337-
DeclContext *newContext) {
6337+
ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
6338+
ValueDecl *decl, DeclContext *newContext) {
63386339
// Make sure we don't clone the decl again for this class, as that would
63396340
// result in multiple definitions of the same symbol.
63406341
std::pair<ValueDecl *, DeclContext *> key = {decl, newContext};
6341-
if (!Impl.clonedBaseMembers.count(key)) {
6342+
auto known = clonedBaseMembers.find(key);
6343+
if (known == clonedBaseMembers.end()) {
63426344
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext);
6343-
Impl.clonedBaseMembers[key] = cloned;
6345+
known = clonedBaseMembers.insert({key, cloned}).first;
63446346
}
6345-
return Impl.clonedBaseMembers[key];
6347+
6348+
return known->second;
6349+
}
6350+
6351+
ValueDecl *ClangImporter::importBaseMemberDecl(ValueDecl *decl,
6352+
DeclContext *newContext) {
6353+
return Impl.importBaseMemberDecl(decl, newContext);
63466354
}
63476355

63486356
void ClangImporter::diagnoseTopLevelValue(const DeclName &name) {

lib/ClangImporter/ImportDecl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3581,6 +3581,12 @@ namespace {
35813581
if (!dc)
35823582
return nullptr;
35833583

3584+
// While importing the DeclContext, we might have imported the decl
3585+
// itself.
3586+
auto known = Impl.importDeclCached(decl, getVersion());
3587+
if (known.has_value())
3588+
return known.value();
3589+
35843590
// TODO: do we want to emit a diagnostic here?
35853591
// Types that are marked as foreign references cannot be stored by value.
35863592
if (auto recordType =
@@ -8761,8 +8767,6 @@ static void loadAllMembersOfSuperclassIfNeeded(ClassDecl *CD) {
87618767
E->loadAllMembers();
87628768
}
87638769

8764-
ValueDecl *cloneBaseMemberDecl(ValueDecl *decl, DeclContext *newContext);
8765-
87668770
void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
87678771
NominalTypeDecl *swiftDecl, const clang::RecordDecl *clangRecord) {
87688772
// Import all of the members.
@@ -8793,7 +8797,7 @@ void ClangImporter::Implementation::loadAllMembersOfRecordDecl(
87938797
// This means we found a member in a C++ record's base class.
87948798
if (swiftDecl->getClangDecl() != clangRecord) {
87958799
// So we need to clone the member into the derived class.
8796-
if (auto newDecl = cloneBaseMemberDecl(cast<ValueDecl>(member), swiftDecl)) {
8800+
if (auto newDecl = importBaseMemberDecl(cast<ValueDecl>(member), swiftDecl)) {
87978801
swiftDecl->addMember(newDecl);
87988802
}
87998803
continue;

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,10 +642,14 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
642642
llvm::MapVector<std::pair<NominalTypeDecl *, Type>,
643643
std::pair<FuncDecl *, FuncDecl *>> cxxSubscripts;
644644

645+
private:
645646
// Keep track of the decls that were already cloned for this specific class.
646647
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
647648
clonedBaseMembers;
648649

650+
ValueDecl *importBaseMemberDecl(ValueDecl *decl, DeclContext *newContext);
651+
652+
public:
649653
// Cache for already-specialized function templates and any thunks they may
650654
// have.
651655
llvm::DenseMap<clang::FunctionDecl *, ValueDecl *>

lib/SILGen/SILGenExpr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6183,6 +6183,11 @@ RValue RValueEmitter::visitConsumeExpr(ConsumeExpr *E, SGFContext C) {
61836183
mv = SGF.B.createMoveValue(E, mv);
61846184
// Set the flag so we check this.
61856185
cast<MoveValueInst>(mv.getValue())->setAllowsDiagnostics(true);
6186+
if (subType.isMoveOnly()) {
6187+
// We need to move-only-check the moved value.
6188+
mv = SGF.B.createMarkMustCheckInst(E, mv,
6189+
MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
6190+
}
61866191
return RValue(SGF, {mv}, subType.getASTType());
61876192
}
61886193

lib/SILOptimizer/Mandatory/MoveOnlyObjectCheckerUtils.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,10 @@ bool swift::siloptimizer::searchForCandidateObjectMarkMustChecks(
133133
}
134134
}
135135

136-
// Any time we have a lexical move_value, we can process it.
136+
// Any time we have a move_value, we can process it.
137137
if (auto *mvi = dyn_cast<MoveValueInst>(mmci->getOperand())) {
138-
if (mvi->isLexical()) {
139-
moveIntroducersToProcess.insert(mmci);
140-
continue;
141-
}
138+
moveIntroducersToProcess.insert(mmci);
139+
continue;
142140
}
143141

144142
if (auto *arg = dyn_cast<SILFunctionArgument>(mmci->getOperand())) {

lib/SILOptimizer/Transforms/AllocBoxToStack.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,22 @@ static void replaceProjectBoxUsers(SILValue heapBox, SILValue stackBox) {
526526
}
527527
}
528528

529+
static void replaceAllNonDebugUsesWith(SILValue value,
530+
SILValue with) {
531+
auto useI = value->use_begin();
532+
while (useI != value->use_end()) {
533+
Operand *op = *useI;
534+
++useI;
535+
// Leave debug instructions on the original value.
536+
if (op->getUser()->isDebugInstruction()) {
537+
continue;
538+
}
539+
540+
// Rewrite all other uses.
541+
op->set(with);
542+
}
543+
}
544+
529545
static void hoistMarkMustCheckInsts(SILValue stackBox,
530546
MarkMustCheckInst::CheckKind checkKind) {
531547
StackList<Operand *> worklist(stackBox->getFunction());
@@ -571,7 +587,9 @@ static void hoistMarkMustCheckInsts(SILValue stackBox,
571587
auto *undef = SILUndef::get(stackBox->getType(), *stackBox->getModule());
572588

573589
auto *mmci = builder.createMarkMustCheckInst(loc, undef, checkKind);
574-
stackBox->replaceAllUsesWith(mmci);
590+
// Leave debug uses on the to-be-promoted box, but hoist all other uses to the
591+
// new mark_must_check.
592+
replaceAllNonDebugUsesWith(stackBox, mmci);
575593
mmci->setOperand(stackBox);
576594
}
577595

lib/Sema/MiscDiagnostics.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4052,9 +4052,40 @@ void swift::performAbstractFuncDeclDiagnostics(AbstractFunctionDecl *AFD) {
40524052
}
40534053
}
40544054

4055+
static void
4056+
diagnoseMoveOnlyPatternMatchSubject(ASTContext &C,
4057+
Expr *subjectExpr) {
4058+
// For now, move-only types must use the `consume` operator to be
4059+
// pattern matched. Pattern matching is only implemented as a consuming
4060+
// operation today, but we don't want to be stuck with that as the default
4061+
// in the fullness of time when we get borrowing pattern matching later.
4062+
4063+
// Don't bother if the subject wasn't given a valid type, or is a copyable
4064+
// type.
4065+
auto subjectType = subjectExpr->getType();
4066+
if (!subjectType
4067+
|| subjectType->hasError()
4068+
|| !subjectType->isPureMoveOnly()) {
4069+
return;
4070+
}
4071+
4072+
// A bare reference to, or load from, a move-only binding must be consumed.
4073+
subjectExpr = subjectExpr->getSemanticsProvidingExpr();
4074+
if (auto load = dyn_cast<LoadExpr>(subjectExpr)) {
4075+
subjectExpr = load->getSubExpr()->getSemanticsProvidingExpr();
4076+
}
4077+
if (isa<DeclRefExpr>(subjectExpr)) {
4078+
C.Diags.diagnose(subjectExpr->getLoc(),
4079+
diag::move_only_pattern_match_not_consumed)
4080+
.fixItInsert(subjectExpr->getStartLoc(), "consume ");
4081+
}
4082+
}
4083+
40554084
// Perform MiscDiagnostics on Switch Statements.
40564085
static void checkSwitch(ASTContext &ctx, const SwitchStmt *stmt,
40574086
DeclContext *DC) {
4087+
diagnoseMoveOnlyPatternMatchSubject(ctx, stmt->getSubjectExpr());
4088+
40584089
// We want to warn about "case .Foo, .Bar where 1 != 100:" since the where
40594090
// clause only applies to the second case, and this is surprising.
40604091
for (auto cs : stmt->getCases()) {
@@ -4816,7 +4847,9 @@ static void checkLabeledStmtConditions(ASTContext &ctx,
48164847

48174848
switch (elt.getKind()) {
48184849
case StmtConditionElement::CK_Boolean:
4850+
break;
48194851
case StmtConditionElement::CK_PatternBinding:
4852+
diagnoseMoveOnlyPatternMatchSubject(ctx, elt.getInitializer());
48204853
break;
48214854
case StmtConditionElement::CK_Availability: {
48224855
auto info = elt.getAvailability();

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,7 @@ bool TypeChecker::typeCheckStmtConditionElement(StmtConditionElement &elt,
876876
bool hadError = TypeChecker::typeCheckBinding(pattern, init, dc, patternType);
877877
elt.setPattern(pattern);
878878
elt.setInitializer(init);
879+
879880
isFalsable |= pattern->isRefutablePattern();
880881
return hadError;
881882
}

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1531,3 +1531,37 @@ public struct UseIdentifierMacro: DeclarationMacro {
15311531
]
15321532
}
15331533
}
1534+
1535+
public struct StaticFooFuncMacro: DeclarationMacro {
1536+
public static func expansion(
1537+
of node: some FreestandingMacroExpansionSyntax,
1538+
in context: some MacroExpansionContext
1539+
) throws -> [DeclSyntax] {
1540+
return [
1541+
"static func foo() {}",
1542+
]
1543+
}
1544+
}
1545+
1546+
public struct SelfAlwaysEqualOperator: DeclarationMacro {
1547+
public static func expansion(
1548+
of node: some FreestandingMacroExpansionSyntax,
1549+
in context: some MacroExpansionContext
1550+
) throws -> [DeclSyntax] {
1551+
return [
1552+
"static func ==(lhs: Self, rhs: Bool) -> Bool { true }",
1553+
]
1554+
}
1555+
}
1556+
1557+
extension SelfAlwaysEqualOperator: MemberMacro {
1558+
public static func expansion(
1559+
of node: AttributeSyntax,
1560+
providingMembersOf decl: some DeclGroupSyntax,
1561+
in context: some MacroExpansionContext
1562+
) throws -> [DeclSyntax] {
1563+
return [
1564+
"static func ==(lhs: Self, rhs: Bool) -> Bool { true }",
1565+
]
1566+
}
1567+
}

test/Macros/macro_expand.swift

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,58 @@ func testLocalVarsFromDeclarationMacros() {
425425
struct TakesVariadic {
426426
#emptyDecl("foo", "bar")
427427
}
428+
429+
// Funkiness with static functions introduced via macro expansions.
430+
@freestanding(declaration, names: named(foo())) public macro staticFooFunc() = #externalMacro(module: "MacroDefinition", type: "StaticFooFuncMacro")
431+
@freestanding(declaration, names: arbitrary) public macro staticFooFuncArbitrary() = #externalMacro(module: "MacroDefinition", type: "StaticFooFuncMacro")
432+
433+
class HasAnExpandedStatic {
434+
#staticFooFunc()
435+
}
436+
437+
class HasAnExpandedStatic2 {
438+
#staticFooFuncArbitrary()
439+
}
440+
441+
func testHasAnExpandedStatic() {
442+
#if TEST_DIAGNOSTICS
443+
foo() // expected-error{{cannot find 'foo' in scope}}
444+
#endif
445+
}
446+
447+
@freestanding(declaration, names: named(==)) public macro addSelfEqualsOperator() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
448+
@freestanding(declaration, names: arbitrary) public macro addSelfEqualsOperatorArbitrary() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
449+
@attached(member, names: named(==)) public macro AddSelfEqualsMemberOperator() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
450+
@attached(member, names: arbitrary) public macro AddSelfEqualsMemberOperatorArbitrary() = #externalMacro(module: "MacroDefinition", type: "SelfAlwaysEqualOperator")
451+
452+
struct HasEqualsSelf {
453+
#addSelfEqualsOperator
454+
}
455+
456+
struct HasEqualsSelf2 {
457+
#addSelfEqualsOperatorArbitrary
458+
}
459+
460+
@AddSelfEqualsMemberOperator
461+
struct HasEqualsSelf3 {
462+
}
463+
464+
@AddSelfEqualsMemberOperatorArbitrary
465+
struct HasEqualsSelf4 {
466+
}
467+
468+
func testHasEqualsSelf(
469+
x: HasEqualsSelf, y: HasEqualsSelf2, z: HasEqualsSelf3, w: HasEqualsSelf4
470+
) {
471+
_ = (x == true)
472+
_ = (y == true)
473+
#if TEST_DIAGNOSTICS
474+
// FIXME: This is technically a bug, because we should be able to find the
475+
// == operator introduced through a member operator. However, we might
476+
// want to change the rule rather than implement this.
477+
_ = (z == true) // expected-error{{binary operator '==' cannot be applied to operands}}
478+
// expected-note@-1{{overloads for '==' exist with these partially matching parameter lists}}
479+
_ = (w == true) // expected-error{{binary operator '==' cannot be applied to operands}}
480+
// expected-note@-1{{overloads for '==' exist with these partially matching parameter lists}}
481+
#endif
482+
}

0 commit comments

Comments
 (0)