Index: clang/include/clang/AST/Decl.h =================================================================== --- clang/include/clang/AST/Decl.h +++ clang/include/clang/AST/Decl.h @@ -1638,6 +1638,14 @@ /// declaration name embedded in the DeclaratorDecl base class. DeclarationNameLoc DNLoc; + /// Storage for diagnostics deferred until this function is codegen'ed (if it + /// ever is). + /// + /// These are rarely used, so we use a pointer-to-vector to save two words + /// inside FunctionDecl. This is mutable because emitting diagnostics (which + /// clears this list) needs to be a logically-const operation. + mutable std::unique_ptr> DeferredDiags; + /// \brief Specify that this function declaration is actually a function /// template specialization. /// @@ -2271,6 +2279,14 @@ /// returns 0. unsigned getMemoryFunctionKind() const; + /// Add a diagnostic to be emitted if and when this function is codegen'ed. + void addDeferredDiag(PartialDiagnosticAt PD); + + /// Gets this object's list of deferred diagnostics, if there are any. + /// + /// Although this is logically const, it clears our list of deferred diags. + std::vector takeDeferredDiags() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { Index: clang/lib/AST/Decl.cpp =================================================================== --- clang/lib/AST/Decl.cpp +++ clang/lib/AST/Decl.cpp @@ -3436,6 +3436,22 @@ return 0; } +void FunctionDecl::addDeferredDiag(PartialDiagnosticAt PD) { + if (!DeferredDiags) + DeferredDiags = llvm::make_unique>(); + DeferredDiags->emplace_back(PD); +} + +std::vector FunctionDecl::takeDeferredDiags() const { + if (!DeferredDiags) + return {}; + assert(!DeferredDiags->empty() && + "DeferredDiags should be non-null only if it's also non-empty."); + auto Ret = std::move(*DeferredDiags); + DeferredDiags.reset(); + return Ret; +} + //===----------------------------------------------------------------------===// // FieldDecl Implementation //===----------------------------------------------------------------------===// Index: clang/lib/CodeGen/CodeGenModule.h =================================================================== --- clang/lib/CodeGen/CodeGenModule.h +++ clang/lib/CodeGen/CodeGenModule.h @@ -490,6 +490,10 @@ /// MDNodes. llvm::DenseMap MetadataIdMap; + /// Diags gathered from FunctionDecl::takeDeferredDiags(). Emitted at the + /// very end of codegen. + std::vector> DeferredDiags; + public: CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts, const PreprocessorOptions &ppopts, Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -497,6 +497,16 @@ EmitVersionIdentMetadata(); EmitTargetMetadata(); + + // Emit any deferred diagnostics gathered during codegen. We didn't emit them + // when we first discovered them because that would have halted codegen, + // preventing us from gathering other deferred diags. + for (const PartialDiagnosticAt &DiagAt : DeferredDiags) { + SourceLocation Loc = DiagAt.first; + const PartialDiagnostic &PD = DiagAt.second; + DiagnosticBuilder Builder(getDiags().Report(Loc, PD.getDiagID())); + PD.Emit(Builder); + } } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { @@ -2872,6 +2882,19 @@ llvm::GlobalValue *GV) { const auto *D = cast(GD.getDecl()); + // Check if this function has diagnostics that should be emitted when we + // codegen it. If so, don't eit this function definition, but don't emit the + // diags just yet. Emitting an error during codegen stops codegen, and we + // want to display as many deferred diags as possible. We'll emit the now + // twice-deferred diags at the very end of codegen. + auto Diags = D->takeDeferredDiags(); + bool HasDiags = !Diags.empty(); + DeferredDiags.insert(DeferredDiags.end(), + std::make_move_iterator(Diags.begin()), + std::make_move_iterator(Diags.end())); + if (HasDiags) + return; + // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::FunctionType *Ty = getTypes().GetFunctionType(FI);