Skip to content

[Swift][Macros] Assertion isConcrete() in ProtocolConformanceRef::getConcrete when expanding @attached member macro on a subclass whose superclass has the same macro applied and the macro plugin is missing #89151

@YuanchengJiang

Description

@YuanchengJiang

Related: #83788

Description

swift reproduce.swift crashes with an assertion failure isConcrete() in ProtocolConformanceRef::getConcrete at ProtocolConformanceRef.h:127 when type-checking a class D that inherits from C, where both are annotated with an @attached(member, conformances:) macro whose plugin cannot be found. When the macro plugin is missing, the conformance introduced by the macro expansion is left in a non-concrete state. The compiler then calls getConcrete() unconditionally on this non-concrete ProtocolConformanceRef during getIntroducedConformances, triggering the assertion.

Reproducer

protocol DefaultInit {
    init()
}

@attached(extension, conformances: DefaultInit)
@attached(member, conformances: DefaultInit, names: named(init()), named(f()))
macro DefaultInit() = #externalMacro(module: "MacroDefinition", type: "RequiredDefaultInitMacro")

@DefaultInit
class C { }

@DefaultInit
class D: C { }

Command

swift reproduce.swift

Expected behavior

When the macro plugin is missing, the compiler should emit an error diagnostic and exit gracefully. It should not crash with an assertion failure. The conformance lookup path in getIntroducedConformances should guard against non-concrete conformance references before calling getConcrete().

Actual behavior

test.swift:6:7: warning: external macro implementation type
  'MacroDefinition.RequiredDefaultInitMacro' could not be found for macro 'DefaultInit()'
test.swift:9:7: error: external macro implementation type
  'MacroDefinition.RequiredDefaultInitMacro' could not be found for macro 'DefaultInit()'

Assertion failed: (isConcrete()), function getConcrete at ProtocolConformanceRef.h:127.

While evaluating request TypeCheckPrimaryFileRequest(source_file "reproduce.swift")
While type-checking 'D'
While evaluating request StoredPropertiesRequest(D)
While evaluating request ExpandSynthesizedMemberMacroRequest(D)

Call chain

TypeCheckPrimaryFileRequest::evaluate
  → typeCheckDecl (class D)
    → NominalTypeDecl::getStoredProperties
      → StoredPropertiesRequest::evaluate
        → ExpandSynthesizedMemberMacroRequest::evaluate
          → expandMembers
            → getIntroducedConformances
              → ConformanceLookupTable::lookupConformance
                → ConformanceLookupTable::getConformance
                  → ProtocolConformanceRef::getConcrete   ← assertion: !isConcrete()

This bug was found by fusion-fuzz

Metadata

Metadata

Assignees

No one assigned

    Labels

    crashBug: A crash, i.e., an abnormal termination of softwaretriage neededThis issue needs more specific labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions