Skip to content
Merged
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: 1 addition & 1 deletion include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
47 changes: 33 additions & 14 deletions include/swift/AST/MacroDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<MissingDefinition *>(opaqueHandle);
}
};

Expand Down
2 changes: 1 addition & 1 deletion include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class DefaultArgumentType;
class ClosureExpr;
class GenericParamList;
class LabeledStmt;
struct MacroDefinition;
class MacroDefinition;
class PrecedenceGroupDecl;
class PropertyWrapperInitializerInfo;
struct PropertyWrapperLValueness;
Expand Down
13 changes: 13 additions & 0 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
};
}
64 changes: 34 additions & 30 deletions lib/Sema/TypeCheckMacros.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions test/Macros/macros_diagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// REQUIRES: OS=macosx

macro stringify<T>(_ value: T) -> (T, String) = _SwiftSyntaxMacros.StringifyMacro
macro missingMacro1(_: Any) = MissingModule.MissingType // expected-note{{'missingMacro1' declared here}}
macro missingMacro2(_: Any) = MissingModule.MissingType

protocol P { }

Expand Down Expand Up @@ -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'}}
}