Author: jlebar Date: Mon Aug 15 15:38:56 2016 New Revision: 278735 URL: http://llvm.org/viewvc/llvm-project?rev=278735&view=rev Log: Add the notion of deferred diagnostics.
Summary: This patch lets you create diagnostics that are emitted if and only if a particular FunctionDecl is codegen'ed. This is necessary for CUDA, where some constructs -- e.g. calls from host+device functions to host functions when compiling for device -- are allowed to appear in semantically-correct programs, but only if they're never codegen'ed. Reviewers: rnk Subscribers: cfe-commits, tra Differential Revision: https://reviews.llvm.org/D23241 Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/AST/Decl.h cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=278735&r1=278734&r2=278735&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Mon Aug 15 15:38:56 2016 @@ -324,6 +324,12 @@ class ASTContext : public RefCountedBase }; llvm::DenseMap<Module*, PerModuleInitializers*> ModuleInitializers; + /// Diagnostics that are emitted if and only if the given function is + /// codegen'ed. Access these through FunctionDecl::addDeferredDiag() and + /// FunctionDecl::takeDeferredDiags(). + llvm::DenseMap<const FunctionDecl *, std::vector<PartialDiagnosticAt>> + DeferredDiags; + public: /// \brief A type synonym for the TemplateOrInstantiation mapping. typedef llvm::PointerUnion<VarTemplateDecl *, MemberSpecializationInfo *> @@ -597,6 +603,11 @@ public: return DiagAllocator; } + decltype(DeferredDiags) &getDeferredDiags() { return DeferredDiags; } + const decltype(DeferredDiags) &getDeferredDiags() const { + return DeferredDiags; + } + const TargetInfo &getTargetInfo() const { return *Target; } const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=278735&r1=278734&r2=278735&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Mon Aug 15 15:38:56 2016 @@ -2271,6 +2271,14 @@ public: /// 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<PartialDiagnosticAt> takeDeferredDiags() const; + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=278735&r1=278734&r2=278735&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Mon Aug 15 15:38:56 2016 @@ -3446,6 +3446,20 @@ unsigned FunctionDecl::getMemoryFunction return 0; } +void FunctionDecl::addDeferredDiag(PartialDiagnosticAt PD) { + getASTContext().getDeferredDiags()[this].push_back(std::move(PD)); +} + +std::vector<PartialDiagnosticAt> FunctionDecl::takeDeferredDiags() const { + auto &DD = getASTContext().getDeferredDiags(); + auto It = DD.find(this); + if (It == DD.end()) + return {}; + auto Ret = std::move(It->second); + DD.erase(It); + return Ret; +} + //===----------------------------------------------------------------------===// // FieldDecl Implementation //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=278735&r1=278734&r2=278735&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Aug 15 15:38:56 2016 @@ -497,6 +497,16 @@ void CodeGenModule::Release() { 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,33 @@ void CodeGenModule::EmitGlobalFunctionDe llvm::GlobalValue *GV) { const auto *D = cast<FunctionDecl>(GD.getDecl()); + // Emit this function's deferred diagnostics, if none of them are errors. If + // any of them are errors, don't codegen the function, but also don't emit any + // of the diagnostics just yet. Emitting an error during codegen stops + // further 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. + // + // (If a function has both error and non-error diags, we don't emit the + // non-error diags here, because order can be significant, e.g. with notes + // that follow errors.) + auto Diags = D->takeDeferredDiags(); + bool HasError = llvm::any_of(Diags, [this](const PartialDiagnosticAt &PDAt) { + return getDiags().getDiagnosticLevel(PDAt.second.getDiagID(), PDAt.first) >= + DiagnosticsEngine::Error; + }); + if (HasError) { + DeferredDiags.insert(DeferredDiags.end(), + std::make_move_iterator(Diags.begin()), + std::make_move_iterator(Diags.end())); + return; + } + for (PartialDiagnosticAt &PDAt : Diags) { + const SourceLocation &Loc = PDAt.first; + const PartialDiagnostic &PD = PDAt.second; + DiagnosticBuilder Builder(getDiags().Report(Loc, PD.getDiagID())); + PD.Emit(Builder); + } + // Compute the function info and LLVM type. const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=278735&r1=278734&r2=278735&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Mon Aug 15 15:38:56 2016 @@ -490,6 +490,10 @@ private: /// MDNodes. llvm::DenseMap<QualType, llvm::Metadata *> MetadataIdMap; + /// Diags gathered from FunctionDecl::takeDeferredDiags(). Emitted at the + /// very end of codegen. + std::vector<std::pair<SourceLocation, PartialDiagnostic>> DeferredDiags; + public: CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts, const PreprocessorOptions &ppopts, _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits