Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -9012,5 +9012,7 @@ GROUPED_WARNING(perf_hint_typealias_uses_existential,ExistentialType,none,
ERROR(unsafe_self_dependent_result_attr_on_invalid_decl,none,
"invalid use of @_unsafeSelfDependentResult", ())

REMARK(macro_expansion_line, none, "macro content: |%0|", (StringRef))

#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"
3 changes: 3 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -651,6 +651,9 @@ namespace swift {
/// Enables dumping macro expansions.
bool DumpMacroExpansions = false;

/// Emits a remark with the content of each macro expansion line, for matching with -verify
bool RemarkMacroExpansions = false;

/// Enables dumping imports for each SourceFile.
bool DumpSourceFileImports = false;

Expand Down
3 changes: 3 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ def verify_generic_signatures : Separate<["-"], "verify-generic-signatures">,
MetaVarName<"<module-name>">,
HelpText<"Verify the generic signatures in the given module">;

def expansion_remarks: Flag<["-"], "Rmacro-expansions">,
HelpText<"Show remarks for each line in macro expansions">;

def show_diagnostics_after_fatal : Flag<["-"], "show-diagnostics-after-fatal">,
HelpText<"Keep emitting subsequent diagnostics after a fatal error">;

Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1774,6 +1774,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.DumpMacroExpansions = Args.hasArg(
OPT_dump_macro_expansions);

Opts.RemarkMacroExpansions = Args.hasArg(
OPT_expansion_remarks);

Opts.DumpSourceFileImports = Args.hasArg(
OPT_dump_source_file_imports);

Expand Down
19 changes: 19 additions & 0 deletions lib/Sema/TypeCheckMacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,21 @@ static CharSourceRange getExpansionInsertionRange(MacroRole role,
llvm_unreachable("unhandled MacroRole");
}

static void remarkMacroExpansionsEmitDiags(ASTContext &ctx, unsigned macroBufferID) {
SourceManager &sourceMgr = ctx.SourceMgr;
CharSourceRange range = sourceMgr.getRangeForBuffer(macroBufferID);
SourceLoc start = range.getStart();
StringRef content(start.getPointer(), range.getByteLength());
size_t newline;
do {
newline = content.find('\n');
StringRef line = content.take_front(newline);
content = content.drop_front(newline + 1);

ctx.Diags.diagnose(SourceLoc::getFromPointer(line.begin()), diag::macro_expansion_line, line);
} while (newline != StringRef::npos);
}

static SourceFile *
createMacroSourceFile(std::unique_ptr<llvm::MemoryBuffer> buffer,
MacroRole role, ASTNode target, DeclContext *dc,
Expand Down Expand Up @@ -1069,6 +1084,10 @@ createMacroSourceFile(std::unique_ptr<llvm::MemoryBuffer> buffer,
originModule = cast<Decl *>(target)->getModuleContextForNameLookup();
performImportResolutionForClangMacroBuffer(*macroSourceFile, originModule);
}

if (ctx.LangOpts.RemarkMacroExpansions)
remarkMacroExpansionsEmitDiags(ctx, macroBufferID);

return macroSourceFile;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct UnstringifyPeerMacro: PeerMacro {
public static func expansion(
of node: AttributeSyntax,
providingPeersOf declaration: some DeclSyntaxProtocol,
in context: some MacroExpansionContext
) throws -> [DeclSyntax] {
do {
let argumentList = node.arguments!.as(LabeledExprListSyntax.self)!
let arguments = [LabeledExprSyntax](argumentList)
let arg = arguments.first!.expression.as(StringLiteralExprSyntax.self)!
let content = arg.representedLiteralValue!
return [DeclSyntax("\(raw: content)")]
}
}
}
36 changes: 36 additions & 0 deletions test/Frontend/DiagnosticVerifier/expansion-remarks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// REQUIRES: swift_swift_parser, executable_test

// RUN: %empty-directory(%t)
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(UnstringifyMacroDefinition) -module-name=UnstringifyMacroDefinition %S/Inputs/macro/unstringify-macro.swift -g -no-toolchain-stdlib-rpath

// RUN: %target-typecheck-verify-swift -swift-version 5 -load-plugin-library %t/%target-library-name(UnstringifyMacroDefinition) -Rmacro-expansions

@attached(peer, names: overloaded)
macro unstringifyPeer(_ s: String) =
#externalMacro(module: "UnstringifyMacroDefinition", type: "UnstringifyPeerMacro")

// expected-note@+1 *{{in expansion of macro 'unstringifyPeer' on global function 'foo()' here}}
@unstringifyPeer("func foo(_ x: Int) {\nlet a = 2\nlet b = x\n}")
func foo() {}
/*
expected-expansion@-2:14{{
expected-remark@1{{macro content: |func foo(_ x: Int) {|}}
expected-remark@2{{macro content: | let a = 2|}}
expected-warning@2{{initialization of immutable value 'a' was never used; consider replacing with assignment to '_' or removing it}}
expected-remark@3{{macro content: | let b = x|}}
expected-warning@3{{initialization of immutable value 'b' was never used; consider replacing with assignment to '_' or removing it}}
expected-remark@4{{macro content: |}|}}
}}
*/

@freestanding(expression) public macro ExprMacro() -> String = #file

func bar() {
// expected-note@+1{{in expansion of macro 'ExprMacro' here}}
let _ = #ExprMacro()
/*
expected-expansion@-2:13{{
expected-remark@1{{macro content: |#file|}}
}}
*/
}