@@ -476,6 +476,104 @@ ExpandPeerMacroRequest::evaluate(Evaluator &evaluator, Decl *decl) const {
476476 return decl->getASTContext ().AllocateCopy (bufferIDs);
477477}
478478
479+ static Identifier makeIdentifier (ASTContext &ctx, StringRef name) {
480+ return ctx.getIdentifier (name);
481+ }
482+
483+ static Identifier makeIdentifier (ASTContext &ctx, std::nullptr_t ) {
484+ return Identifier ();
485+ }
486+
487+ // / Diagnose macro expansions that produce any of the following declarations:
488+ // / - Import declarations
489+ // / - Operator and precedence group declarations
490+ // / - Macro declarations
491+ // / - Extensions
492+ // / - Types with `@main` attributes
493+ // / - Top-level default literal type overrides
494+ // / - Value decls with names not covered by the macro declaration.
495+ static void validateMacroExpansion (SourceFile *expansionBuffer,
496+ MacroDecl *macro,
497+ ValueDecl *attachedTo,
498+ MacroRole role) {
499+ // Gather macro-introduced names
500+ llvm::SmallVector<DeclName, 2 > introducedNames;
501+ macro->getIntroducedNames (role, attachedTo, introducedNames);
502+
503+ llvm::SmallDenseSet<DeclName, 2 > coversName (introducedNames.begin (),
504+ introducedNames.end ());
505+
506+ for (auto *decl : expansionBuffer->getTopLevelDecls ()) {
507+ auto &ctx = decl->getASTContext ();
508+
509+ // Certain macro roles can generate special declarations.
510+ if ((isa<AccessorDecl>(decl) && role == MacroRole::Accessor) ||
511+ (isa<ExtensionDecl>(decl) && role == MacroRole::Conformance)) {
512+ continue ;
513+ }
514+
515+ // Diagnose invalid declaration kinds.
516+ if (isa<ImportDecl>(decl) ||
517+ isa<OperatorDecl>(decl) ||
518+ isa<PrecedenceGroupDecl>(decl) ||
519+ isa<MacroDecl>(decl) ||
520+ isa<ExtensionDecl>(decl)) {
521+ decl->diagnose (diag::invalid_decl_in_macro_expansion,
522+ decl->getDescriptiveKind ());
523+ decl->setInvalid ();
524+
525+ if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
526+ extension->setExtendedNominal (nullptr );
527+ }
528+
529+ continue ;
530+ }
531+
532+ // Diagnose `@main` types.
533+ if (auto *mainAttr = decl->getAttrs ().getAttribute <MainTypeAttr>()) {
534+ ctx.Diags .diagnose (mainAttr->getLocation (),
535+ diag::invalid_main_type_in_macro_expansion);
536+ mainAttr->setInvalid ();
537+ }
538+
539+ // Diagnose default literal type overrides.
540+ if (auto *typeAlias = dyn_cast<TypeAliasDecl>(decl)) {
541+ auto name = typeAlias->getBaseIdentifier ();
542+ #define EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME (_, __, typeName, \
543+ supportsOverride) \
544+ if (supportsOverride && name == makeIdentifier (ctx, typeName)) { \
545+ typeAlias->diagnose (diag::literal_type_in_macro_expansion, \
546+ makeIdentifier (ctx, typeName)); \
547+ typeAlias->setInvalid (); \
548+ continue ; \
549+ }
550+ #include " swift/AST/KnownProtocols.def"
551+ #undef EXPRESSIBLE_BY_LITERAL_PROTOCOL_WITH_NAME
552+ }
553+
554+ // Diagnose value decls with names not covered by the macro
555+ if (auto *value = dyn_cast<ValueDecl>(decl)) {
556+ auto baseName = value->getBaseName ();
557+ if (baseName.isSpecial ()) {
558+ baseName = ctx.getIdentifier (baseName.userFacingName ());
559+ }
560+
561+ // $-prefixed names are unique names. These are always allowed.
562+ if (baseName.getIdentifier ().hasDollarPrefix ()) {
563+ continue ;
564+ }
565+
566+ if (coversName.count (baseName) ||
567+ coversName.count (MacroDecl::getArbitraryName ())) {
568+ continue ;
569+ }
570+
571+ value->diagnose (diag::invalid_macro_introduced_name,
572+ baseName, macro->getBaseName ());
573+ }
574+ }
575+ }
576+
479577// / Determine whether the given source file is from an expansion of the given
480578// / macro.
481579static bool isFromExpansionOfMacro (SourceFile *sourceFile, MacroDecl *macro,
@@ -1101,6 +1199,8 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr,
11011199 /* parsingOpts=*/ {}, /* isPrimary=*/ false );
11021200 macroSourceFile->setImports (declSourceFile->getImports ());
11031201
1202+ validateMacroExpansion (macroSourceFile, macro,
1203+ dyn_cast<ValueDecl>(attachedTo), role);
11041204 return macroSourceFile;
11051205}
11061206
0 commit comments