Skip to content

Commit 47ed6e7

Browse files
committed
Disallow expression macro as default argument
Using as a sub expression in default argument still allowed as expression macros behave the same as built-in magic literals
1 parent 8624e9a commit 47ed6e7

File tree

3 files changed

+41
-0
lines changed

3 files changed

+41
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7326,6 +7326,9 @@ ERROR(extension_macro_invalid_conformance,none,
73267326
ERROR(macro_attached_to_invalid_decl,none,
73277327
"'%0' macro cannot be attached to %1 (%base2)",
73287328
(StringRef, DescriptiveDeclKind, const Decl *))
7329+
ERROR(macro_as_default_argument, none,
7330+
"non-built-in macro cannot be used as the default argument",
7331+
())
73297332
ERROR(conformance_macro,none,
73307333
"conformance macros are replaced by extension macros",
73317334
())

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,12 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator,
11321132
auto *initExpr = param->getStructuralDefaultExpr();
11331133
assert(initExpr);
11341134

1135+
// Prohibit default argument that is a non-built-in macro to avoid confusion.
1136+
if (isa<MacroExpansionExpr>(initExpr)) {
1137+
ctx.Diags.diagnose(initExpr->getLoc(), diag::macro_as_default_argument);
1138+
return new (ctx) ErrorExpr(initExpr->getSourceRange(), ErrorType::get(ctx));
1139+
}
1140+
11351141
// If the param has an error type, there's no point type checking the default
11361142
// expression, unless we are type checking for code completion, in which case
11371143
// the default expression might contain the code completion token.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %empty-directory(%t)
4+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
5+
6+
// RUN: not %target-build-swift -typecheck -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) %s 2>&1 | %FileCheck %s
7+
8+
@freestanding(expression)
9+
macro MagicLine() -> Int = #externalMacro(module: "MacroDefinition", type: "MagicLineMacro")
10+
11+
struct LineContainer {
12+
let line: Int
13+
}
14+
15+
func partOfDefaultArgumentOkay(container: LineContainer = .init(line: #MagicLine)) {
16+
print(container.line)
17+
}
18+
19+
func parenthesizedExpansionAtDeclOkay(line: Int = (#MagicLine)) {
20+
print(line)
21+
}
22+
23+
func builtInOkay(line: Int = #line) {
24+
print(line)
25+
}
26+
27+
// CHECK: non-built-in macro cannot be used as the default argument
28+
func asDefaultArgument(line: Int = #MagicLine) {
29+
print(line)
30+
}
31+
32+
testAsDefaultArgument()

0 commit comments

Comments
 (0)