From 54625a3a709ec506f741b229fd8669fe201a7dbe Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 12 Dec 2022 13:18:13 -0800 Subject: [PATCH] Only diagnose a missing external macro definition when we try to expand --- include/swift/AST/DiagnosticsSema.def | 2 +- include/swift/AST/MacroDefinition.h | 47 ++++++++++++++------ include/swift/AST/TypeCheckRequests.h | 2 +- lib/AST/Decl.cpp | 13 ++++++ lib/Sema/TypeCheckMacros.cpp | 64 ++++++++++++++------------- test/Macros/macros_diagnostics.swift | 6 +++ 6 files changed, 88 insertions(+), 46 deletions(-) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index efc08460c5ad8..43c71febbb351 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -6746,7 +6746,7 @@ ERROR(macro_undefined,PointsToFirstBadToken, "macro %0 is undefined; use `-load-plugin-library` to specify dynamic " "libraries that contain this macro", (Identifier)) ERROR(external_macro_not_found,none, - "external implementation struct '%0.%1' could not be found in for " + "external macro implementation type '%0.%1' could not be found for " "macro %2; the type must be public and provided via " "'-load-plugin-library'", (StringRef, StringRef, DeclName)) NOTE(macro_note, none, diff --git a/include/swift/AST/MacroDefinition.h b/include/swift/AST/MacroDefinition.h index e9d309d2a93c2..f5c611abf4388 100644 --- a/include/swift/AST/MacroDefinition.h +++ b/include/swift/AST/MacroDefinition.h @@ -23,21 +23,33 @@ namespace swift { /// Provides the definition of a macro. -struct MacroDefinition { - /// The kind of macro, which determines how it can be used in source code. +class MacroDefinition { +public: + /// The kind of macro, which determines how it can be used in source code. enum Kind: uint8_t { - /// An expression macro. + /// An expression macro. Expression, }; + /// Describes a missing macro definition. + struct MissingDefinition { + Identifier externalModuleName; + Identifier externalMacroTypeName; + }; + /// Describes how the macro is implemented. enum class ImplementationKind: uint8_t { + /// The macro has no definition. + Undefined, + + /// The macro has a definition, but it could not be found. + Missing, + /// The macro is in the same process as the compiler, whether built-in or /// loaded via a compiler plugin. InProcess, }; -public: Kind kind; ImplementationKind implKind; @@ -48,25 +60,32 @@ struct MacroDefinition { : kind(kind), implKind(implKind), opaqueHandle(opaqueHandle) { } public: - static MacroDefinition forInvalid() { + static MacroDefinition forUndefined() { return MacroDefinition{ - Kind::Expression, ImplementationKind::InProcess, nullptr + Kind::Expression, ImplementationKind::Undefined, nullptr }; } + static MacroDefinition forMissing( + ASTContext &ctx, + Identifier externalModuleName, + Identifier externalMacroTypeName + ); + static MacroDefinition forInProcess(Kind kind, void *opaqueHandle) { return MacroDefinition{kind, ImplementationKind::InProcess, opaqueHandle}; } - bool isInvalid() const { return opaqueHandle == nullptr; } - - explicit operator bool() const { return !isInvalid(); } + /// Return the opaque handle for an in-process macro definition. + void *getInProcessOpaqueHandle() const { + assert(implKind == ImplementationKind::InProcess); + return opaqueHandle; + } - void *getAsInProcess() const { - switch (implKind) { - case ImplementationKind::InProcess: - return opaqueHandle; - } + /// Return more information about a missing macro definition. + MissingDefinition *getMissingDefinition() const { + assert(implKind == ImplementationKind::Missing); + return static_cast(opaqueHandle); } }; diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 21ada6afc208d..a1e6197a58d19 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -48,7 +48,7 @@ class DefaultArgumentType; class ClosureExpr; class GenericParamList; class LabeledStmt; -struct MacroDefinition; +class MacroDefinition; class PrecedenceGroupDecl; class PropertyWrapperInitializerInfo; struct PropertyWrapperLValueness; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d8f8301b197b7..71d1ab1f544b0 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -32,6 +32,7 @@ #include "swift/AST/GenericSignature.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" +#include "swift/AST/MacroDefinition.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/NameLookupRequests.h" @@ -9682,3 +9683,15 @@ SourceRange MacroExpansionDecl::getSourceRange() const { return SourceRange(PoundLoc, endLoc); } + +MacroDefinition MacroDefinition::forMissing( + ASTContext &ctx, Identifier externalModuleName, + Identifier externalMacroTypeName +) { + auto def = ctx.AllocateObjectCopy( + MissingDefinition{externalModuleName, externalMacroTypeName} + ); + return MacroDefinition{ + Kind::Expression, ImplementationKind::Missing, def + }; +} diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 7735e0df90e38..61314f6d9fab2 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -119,12 +119,8 @@ MacroDefinition MacroDefinitionRequest::evaluate( } #endif - ctx.Diags.diagnose( - macro, diag::external_macro_not_found, macro->externalModuleName.str(), - macro->externalMacroTypeName.str(), macro->getName()); - // FIXME: Can we give more actionable advice? - - return MacroDefinition::forInvalid(); + return MacroDefinition::forMissing( + ctx, macro->externalModuleName, macro->externalMacroTypeName); } #if SWIFT_SWIFT_PARSER @@ -150,35 +146,43 @@ Expr *swift::expandMacroExpr( auto macroDef = evaluateOrDefault( ctx.evaluator, MacroDefinitionRequest{macro}, - MacroDefinition::forInvalid()); - if (!macroDef) { + MacroDefinition::forUndefined()); + switch (macroDef.implKind) { + case MacroDefinition::ImplementationKind::Undefined: + // Already diagnosed as an error elsewhere. + return nullptr; + + case MacroDefinition::ImplementationKind::Missing: { + auto missingInfo = macroDef.getMissingDefinition(); + ctx.Diags.diagnose( + expr->getLoc(), diag::external_macro_not_found, + missingInfo->externalModuleName.str(), + missingInfo->externalMacroTypeName.str(), macro->getName()); + macro->diagnose(diag::decl_declared_here, macro->getName()); return nullptr; } - { + case MacroDefinition::ImplementationKind::InProcess: { PrettyStackTraceExpr debugStack(ctx, "expanding macro", expr); - switch (macroDef.implKind) { - case MacroDefinition::ImplementationKind::InProcess: { - // Builtin macros are handled via ASTGen. - auto astGenSourceFile = sourceFile->exportedSourceFile; - if (!astGenSourceFile) - return nullptr; - - const char *evaluatedSourceAddress; - ptrdiff_t evaluatedSourceLength; - swift_ASTGen_evaluateMacro( - &ctx.Diags, - macroDef.getAsInProcess(), - astGenSourceFile, expr->getStartLoc().getOpaquePointerValue(), - &evaluatedSourceAddress, &evaluatedSourceLength); - if (!evaluatedSourceAddress) - return nullptr; - evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress, - (size_t)evaluatedSourceLength); - break; - } - } + // Builtin macros are handled via ASTGen. + auto astGenSourceFile = sourceFile->exportedSourceFile; + if (!astGenSourceFile) + return nullptr; + + const char *evaluatedSourceAddress; + ptrdiff_t evaluatedSourceLength; + swift_ASTGen_evaluateMacro( + &ctx.Diags, + macroDef.getInProcessOpaqueHandle(), + astGenSourceFile, expr->getStartLoc().getOpaquePointerValue(), + &evaluatedSourceAddress, &evaluatedSourceLength); + if (!evaluatedSourceAddress) + return nullptr; + evaluatedSource = NullTerminatedStringRef(evaluatedSourceAddress, + (size_t)evaluatedSourceLength); + break; + } } // Figure out a reasonable name for the macro expansion buffer. diff --git a/test/Macros/macros_diagnostics.swift b/test/Macros/macros_diagnostics.swift index 63d671ae4cdd1..c14eadf4cf910 100644 --- a/test/Macros/macros_diagnostics.swift +++ b/test/Macros/macros_diagnostics.swift @@ -2,6 +2,8 @@ // REQUIRES: OS=macosx macro stringify(_ value: T) -> (T, String) = _SwiftSyntaxMacros.StringifyMacro +macro missingMacro1(_: Any) = MissingModule.MissingType // expected-note{{'missingMacro1' declared here}} +macro missingMacro2(_: Any) = MissingModule.MissingType protocol P { } @@ -38,3 +40,7 @@ func test(a: Int, b: Int) { func shadow(a: Int, b: Int, stringify: Int) { _ = #stringify(a + b) } + +func testMissing() { + #missingMacro1("hello") // expected-error{{external macro implementation type 'MissingModule.MissingType' could not be found for macro 'missingMacro1'; the type must be public and provided via '-load-plugin-library'}} +}