This fixes PR31863, a regression introduced in r276159.
Consider this snippet:
struct FVector;
struct FVector {};
struct FBox {
FVector Min; FBox(int);
};
namespace {
FBox InvalidBoundingBox(0);
}
While parsing the DECL_VAR for 'struct FBox', clang recursively read all the
dep decls until it finds the DECL_CXX_RECORD forward declaration for 'struct
FVector'. Then, it resumes all the way up back to DECL_VAR handling in
ReadDeclRecord, where it checks if isConsumerInterestedIn for the decl.
One of the condition for isConsumerInterestedIn to return false is if the
VarDecl is imported from a module D->getImportedOwningModule(), because it
will get emitted when we import the relevant module. However, before checking
if it comes from a module, clang checks if Ctx.DeclMustBeEmitted(D), which
triggers the emission of 'struct FBox'. Since one of its fields is still
incomplete, it crashes.
Instead, check if D->getImportedOwningModule() is true before calling
Ctx.DeclMustBeEmitted(D).
It's not locally obvious why the order matters. Can you add a comment explaining why you need to check getImportedOwningModule first? It might be worth splitting Ctx.DeclMustBeEmitted into its own; e.g.,
// An ImportDecl or VarDecl imported from a module will get emitted when // we import the relevant module. if ((isa<ImportDecl>(D) || isa<VarDecl>(D)) && D->getImportedOwningModule()) // Only check DeclMustBeEmitted if D has been fully imported, since it may // emit D as a side effect. if (Ctx.DeclMustBeEmitted(D)) return false;but anything that prevents someone from swapping the conditions when they refactor this would be good enough I think.