https://github.com/AnonMiraj updated https://github.com/llvm/llvm-project/pull/206363
>From 959899a60e675694ab37bbebad73be8b3ee65f2c Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Sun, 28 Jun 2026 22:27:23 +0300 Subject: [PATCH 01/11] [clang] Don't add comments to the AST if not requested --- clang/include/clang/Lex/PreprocessorOptions.h | 5 ++++ clang/include/clang/Sema/Sema.h | 5 ++++ clang/lib/Frontend/ASTUnit.cpp | 6 ++++ clang/lib/Parse/Parser.cpp | 11 +++++-- clang/lib/Sema/Sema.cpp | 29 +++++++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index 4d1a30712836f..5d695e5f0e875 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -157,6 +157,11 @@ class PreprocessorOptions { /// clients don't use them. bool WriteCommentListToPCH = true; + /// Force the front end to retain all documentation comments in the AST, even + /// when no comment consuming diagnostic or language option is enabled. Tools + /// that query comments after parsing set this + bool RetainComments = false; + /// When enabled, preprocessor is in a mode for parsing a single file only. /// /// Disables #includes of other files and if there are unresolved identifiers diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d43b6954196a2..a1d07bdcef872 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1132,6 +1132,11 @@ class Sema final : public SemaBase { void ActOnComment(SourceRange Comment); + /// Returns true if a comment at \p Loc should be retained in the AST + /// (some consumer such as -Wdocumentation, -fparse-all-comments, code + /// completion, or AST-file serialization may read it back). + bool shouldRetainCommentsFromLexer(SourceLocation Loc) const; + /// Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 75e4f7772f47c..0fc9625a6fae8 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1533,6 +1533,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( // We'll manage file buffers ourselves. CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; + // libclang and other ASTUnit clients query documentation comments after + // parsing, so keep them in the AST. + CI->getPreprocessorOpts().RetainComments = true; CI->getFrontendOpts().DisableFree = false; ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts(), AST->getFileManager().getVirtualFileSystem()); @@ -1641,6 +1644,9 @@ bool ASTUnit::LoadFromCompilerInvocation( // We'll manage file buffers ourselves. Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; + // libclang and other ASTUnit clients query documentation comments after + // parsing, so keep them in the AST. + Invocation->getPreprocessorOpts().RetainComments = true; Invocation->getFrontendOpts().DisableFree = false; getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts(), diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 6a21acd9dc4ef..e8794ad9f44c9 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -74,8 +74,12 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) // destructor. initializePragmaHandlers(); - CommentSemaHandler.reset(new ActionCommentHandler(actions)); - PP.addCommentHandler(CommentSemaHandler.get()); + // Only install the comment handler when some consumer may read documentation + // comments back. + if (actions.shouldRetainCommentsFromLexer(SourceLocation())) { + CommentSemaHandler.reset(new ActionCommentHandler(actions)); + PP.addCommentHandler(CommentSemaHandler.get()); + } PP.setCodeCompletionHandler(*this); @@ -480,7 +484,8 @@ Parser::~Parser() { resetPragmaHandlers(); - PP.removeCommentHandler(CommentSemaHandler.get()); + if (CommentSemaHandler) + PP.removeCommentHandler(CommentSemaHandler.get()); PP.clearCodeCompletionHandler(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 9f962912148ab..70f5c95623135 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -24,6 +24,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/DarwinSDKInfo.h" +#include "clang/Basic/DiagnosticComment.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -31,6 +32,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ExternalSemaSource.h" @@ -2727,10 +2729,37 @@ LambdaScopeInfo *Sema::getCurGenericLambda() { } +bool Sema::shouldRetainCommentsFromLexer(SourceLocation Loc) const { + if (LangOpts.CommentOpts.ParseAllComments) + return true; + + if (PP.getPreprocessorOpts().RetainComments) + return true; + + // When building a PCH the comments are serialized into the AST file + // so downstream consumers like clangd) can retrieve documentation, and the + // incremental/REPL front end may query them interactively. + if (TUKind != TU_Complete) + return true; + + if (PP.isCodeCompletionEnabled()) + return true; + + // Keep the comment if -Wdocumentation is enabled at its location (checking + // the location handles warnings turned on by `#pragma clang diagnostic`). + if (!Diags.isIgnored(diag::warn_doc_param_not_found, Loc) || + !Diags.isIgnored(diag::warn_unknown_comment_command_name, Loc)) + return true; + + return false; +} + void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; + if (!shouldRetainCommentsFromLexer(Comment.getBegin())) + return; RawComment RC(SourceMgr, Comment, LangOpts.CommentOpts, false); if (RC.isAlmostTrailingComment() || RC.hasUnsupportedSplice(SourceMgr)) { SourceRange MagicMarkerRange(Comment.getBegin(), >From eb2eb83d577ee89421a6cdb305b0895f144f1bdd Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Sun, 28 Jun 2026 22:41:05 +0300 Subject: [PATCH 02/11] fix formatting --- clang/lib/Sema/Sema.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 70f5c95623135..668c9032939e7 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2728,7 +2728,6 @@ LambdaScopeInfo *Sema::getCurGenericLambda() { return nullptr; } - bool Sema::shouldRetainCommentsFromLexer(SourceLocation Loc) const { if (LangOpts.CommentOpts.ParseAllComments) return true; >From 65cd5e1e127f65b5c7c9da0c7ba7496d39e25c5c Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Sun, 28 Jun 2026 23:38:28 +0300 Subject: [PATCH 03/11] retain comments with -fretain-comments so --doxygen works --- clang-tools-extra/clang-doc/tool/ClangDocMain.cpp | 3 ++- clang/include/clang/Options/Options.td | 6 ++++++ clang/lib/Driver/ToolChains/Clang.cpp | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index 00290d7cdc74b..0b81a3cb20351 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -285,7 +285,8 @@ Example usage for a project using a compile commands database: llvm::outs() << "Emiting docs in " << Format << " format.\n"; auto G = ExitOnErr(doc::findGeneratorByName(Format)); - ArgumentsAdjuster ArgAdjuster; + ArgumentsAdjuster ArgAdjuster = getInsertArgumentAdjuster( + "-fretain-comments", tooling::ArgumentInsertPosition::END); if (!DoxygenOnly) ArgAdjuster = combineAdjusters( getInsertArgumentAdjuster("-fparse-all-comments", diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 4afb089e8a51f..e36d1f39d9c9e 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2173,6 +2173,12 @@ defm define_target_os_macros : OptInCC1FFlag<"define-target-os-macros", def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group<f_clang_Group>, Visibility<[ClangOption, CC1Option]>, MarshallingInfoFlag<LangOpts<"CommentOpts.ParseAllComments">>; +def fretain_comments : Flag<["-"], "fretain-comments">, Group<f_clang_Group>, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Retain documentation comments in the AST even when no diagnostic or " + "language option would otherwise require them (e.g. for tools that " + "query comments after parsing)">, + MarshallingInfoFlag<PreprocessorOpts<"RetainComments">>; def frecord_command_line : Flag<["-"], "frecord-command-line">, DocBrief<[{Generate a section named ".GCC.command.line" containing the driver command-line. After linking, the section may contain multiple command diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 8c9b98795b194..7ea76f34da4a9 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -8113,6 +8113,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); // Forward -fparse-all-comments to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); + // Forward -fretain-comments to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fretain_comments); // Turn -fplugin=name.so into -load name.so for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) { >From 5124a5119d43c0e314d80c7dc325dcd45b8089fa Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Mon, 29 Jun 2026 09:40:32 +0300 Subject: [PATCH 04/11] fix ci --- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 3 +++ clang/lib/Frontend/FrontendActions.cpp | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 85da480fb67a6..6c6076e889f5a 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -448,6 +448,9 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { } bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { + // ExtractAPI reads documentation comments off the AST + CI.getPreprocessorOpts().RetainComments = true; + auto &Inputs = CI.getFrontendOpts().Inputs; if (Inputs.empty()) return true; diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 4ef94c1991ee2..9c762706f7f40 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -85,6 +85,8 @@ ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::unique_ptr<ASTConsumer> ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { + // Dumping the AST shows documentation comments + CI.getPreprocessorOpts().RetainComments = true; const FrontendOptions &Opts = CI.getFrontendOpts(); return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter, Opts.ASTDumpDecls, Opts.ASTDumpAll, @@ -249,6 +251,10 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, bool GenerateModuleInterfaceAction::PrepareToExecuteAction( CompilerInstance &CI) { + // Documentation comments must still be serialized into the BMI + // so importers can query them + CI.getPreprocessorOpts().RetainComments = true; + for (const auto &FIF : CI.getFrontendOpts().Inputs) { if (const auto InputFormat = FIF.getKind().getFormat(); InputFormat != InputKind::Format::Source) { >From 5c6724f2ed2e08accf3da05a3057e3060f09decf Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Mon, 29 Jun 2026 21:56:53 +0300 Subject: [PATCH 05/11] Move RetainComments and RetainCommentsFromSystemHeaders into CommentOptions --- clang-tools-extra/clangd/Compiler.cpp | 2 +- clang-tools-extra/clangd/index/IndexAction.cpp | 2 +- clang/include/clang/Basic/CommentOptions.h | 8 ++++++++ clang/include/clang/Basic/LangOptions.def | 2 -- clang/include/clang/Lex/PreprocessorOptions.h | 5 ----- clang/include/clang/Options/Options.td | 4 ++-- clang/lib/AST/ASTContext.cpp | 2 +- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp | 4 ++-- clang/lib/Frontend/ASTUnit.cpp | 4 ++-- clang/lib/Frontend/FrontendActions.cpp | 8 ++++---- clang/lib/Sema/Sema.cpp | 4 ++-- 11 files changed, 23 insertions(+), 22 deletions(-) diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 4644cd75c0833..095c765e518dd 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -121,7 +121,7 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, // createInvocationFromCommandLine sets DisableFree. CI->getFrontendOpts().DisableFree = false; CI->getLangOpts().CommentOpts.ParseAllComments = true; - CI->getLangOpts().RetainCommentsFromSystemHeaders = true; + CI->getLangOpts().CommentOpts.RetainCommentsFromSystemHeaders = true; disableUnsupportedOptions(*CI); return CI; diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp index 489c61f1ff424..bd662e3c90b1f 100644 --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -167,7 +167,7 @@ class IndexAction : public ASTFrontendAction { bool BeginInvocation(CompilerInstance &CI) override { // We want all comments, not just the doxygen ones. CI.getLangOpts().CommentOpts.ParseAllComments = true; - CI.getLangOpts().RetainCommentsFromSystemHeaders = true; + CI.getLangOpts().CommentOpts.RetainCommentsFromSystemHeaders = true; // Index the whole file even if there are warnings and -Werror is set. // Avoids some analyses too. Set in two places as we're late to the party. CI.getDiagnosticOpts().IgnoreWarnings = true; diff --git a/clang/include/clang/Basic/CommentOptions.h b/clang/include/clang/Basic/CommentOptions.h index 7d142fc32f511..73e7cba91cca8 100644 --- a/clang/include/clang/Basic/CommentOptions.h +++ b/clang/include/clang/Basic/CommentOptions.h @@ -30,6 +30,14 @@ struct CommentOptions { /// Treat ordinary comments as documentation comments. bool ParseAllComments = false; + /// Force the front end to retain all documentation comments in the AST, even + /// when no comment consuming diagnostic or language option is enabled. Tools + /// that query comments after parsing set this. + bool RetainComments = false; + + /// Retain documentation comments from system headers in the AST. + bool RetainCommentsFromSystemHeaders = false; + CommentOptions() = default; }; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 1fb491a54a278..8c265090f0238 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -401,8 +401,6 @@ LANGOPT(ApplePragmaPack, 1, 0, NotCompatible, "Apple gcc-compatible #pragma pack LANGOPT(XLPragmaPack, 1, 0, NotCompatible, "IBM XL #pragma pack handling") -LANGOPT(RetainCommentsFromSystemHeaders, 1, 0, Compatible, "retain documentation comments from system headers in the AST") - LANGOPT(APINotes, 1, 0, NotCompatible, "use external API notes") LANGOPT(APINotesModules, 1, 0, NotCompatible, "use module-based external API notes") LANGOPT(SwiftVersionIndependentAPINotes, 1, 0, NotCompatible, "use external API notes capturing all versions") diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index 5d695e5f0e875..4d1a30712836f 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -157,11 +157,6 @@ class PreprocessorOptions { /// clients don't use them. bool WriteCommentListToPCH = true; - /// Force the front end to retain all documentation comments in the AST, even - /// when no comment consuming diagnostic or language option is enabled. Tools - /// that query comments after parsing set this - bool RetainComments = false; - /// When enabled, preprocessor is in a mode for parsing a single file only. /// /// Disables #includes of other files and if there are unresolved identifiers diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index e36d1f39d9c9e..2a8fc61383ca2 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2178,7 +2178,7 @@ def fretain_comments : Flag<["-"], "fretain-comments">, Group<f_clang_Group>, HelpText<"Retain documentation comments in the AST even when no diagnostic or " "language option would otherwise require them (e.g. for tools that " "query comments after parsing)">, - MarshallingInfoFlag<PreprocessorOpts<"RetainComments">>; + MarshallingInfoFlag<LangOpts<"CommentOpts.RetainComments">>; def frecord_command_line : Flag<["-"], "frecord-command-line">, DocBrief<[{Generate a section named ".GCC.command.line" containing the driver command-line. After linking, the section may contain multiple command @@ -3890,7 +3890,7 @@ defm implicit_modules : BoolFOption<"implicit-modules", [NoXarchOption], [ClangOption, CLOption]>>; def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group<f_Group>, Visibility<[ClangOption, CC1Option]>, - MarshallingInfoFlag<LangOpts<"RetainCommentsFromSystemHeaders">>; + MarshallingInfoFlag<LangOpts<"CommentOpts.RetainCommentsFromSystemHeaders">>; def fmodule_header : Flag <["-"], "fmodule-header">, Group<f_Group>, Visibility<[ClangOption, CLOption]>, HelpText<"Build a C++20 Header Unit from a header">; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2228811546c0f..57f271eb4e775 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -357,7 +357,7 @@ RawComment *ASTContext::getRawCommentNoCache(RawCommentLookupKey Key) const { } void ASTContext::addComment(const RawComment &RC) { - assert(LangOpts.RetainCommentsFromSystemHeaders || + assert(LangOpts.CommentOpts.RetainCommentsFromSystemHeaders || !SourceMgr.isInSystemHeader(RC.getSourceRange().getBegin())); Comments.addComment(RC, LangOpts.CommentOpts, BumpAlloc); } diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 6c6076e889f5a..569e600d091cc 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -448,8 +448,8 @@ ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { } bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { - // ExtractAPI reads documentation comments off the AST - CI.getPreprocessorOpts().RetainComments = true; + // ExtractAPI reads documentation comments off the AST. + CI.getLangOpts().CommentOpts.RetainComments = true; auto &Inputs = CI.getFrontendOpts().Inputs; if (Inputs.empty()) diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 0fc9625a6fae8..738fe99cef46b 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1535,7 +1535,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( CI->getPreprocessorOpts().RetainRemappedFileBuffers = true; // libclang and other ASTUnit clients query documentation comments after // parsing, so keep them in the AST. - CI->getPreprocessorOpts().RetainComments = true; + CI->getLangOpts().CommentOpts.RetainComments = true; CI->getFrontendOpts().DisableFree = false; ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts(), AST->getFileManager().getVirtualFileSystem()); @@ -1646,7 +1646,7 @@ bool ASTUnit::LoadFromCompilerInvocation( Invocation->getPreprocessorOpts().RetainRemappedFileBuffers = true; // libclang and other ASTUnit clients query documentation comments after // parsing, so keep them in the AST. - Invocation->getPreprocessorOpts().RetainComments = true; + Invocation->getLangOpts().CommentOpts.RetainComments = true; Invocation->getFrontendOpts().DisableFree = false; getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts(), diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 9c762706f7f40..93e68dc1fcf51 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -85,8 +85,8 @@ ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { std::unique_ptr<ASTConsumer> ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - // Dumping the AST shows documentation comments - CI.getPreprocessorOpts().RetainComments = true; + // Dumping the AST shows documentation comments. + CI.getLangOpts().CommentOpts.RetainComments = true; const FrontendOptions &Opts = CI.getFrontendOpts(); return CreateASTDumper(nullptr /*Dump to stdout.*/, Opts.ASTDumpFilter, Opts.ASTDumpDecls, Opts.ASTDumpAll, @@ -252,8 +252,8 @@ GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, bool GenerateModuleInterfaceAction::PrepareToExecuteAction( CompilerInstance &CI) { // Documentation comments must still be serialized into the BMI - // so importers can query them - CI.getPreprocessorOpts().RetainComments = true; + // so importers can query them. + CI.getLangOpts().CommentOpts.RetainComments = true; for (const auto &FIF : CI.getFrontendOpts().Inputs) { if (const auto InputFormat = FIF.getKind().getFormat(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 668c9032939e7..b8854beeda565 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2732,7 +2732,7 @@ bool Sema::shouldRetainCommentsFromLexer(SourceLocation Loc) const { if (LangOpts.CommentOpts.ParseAllComments) return true; - if (PP.getPreprocessorOpts().RetainComments) + if (LangOpts.CommentOpts.RetainComments) return true; // When building a PCH the comments are serialized into the AST file @@ -2754,7 +2754,7 @@ bool Sema::shouldRetainCommentsFromLexer(SourceLocation Loc) const { } void Sema::ActOnComment(SourceRange Comment) { - if (!LangOpts.RetainCommentsFromSystemHeaders && + if (!LangOpts.CommentOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; if (!shouldRetainCommentsFromLexer(Comment.getBegin())) >From 55b62e3bb498d2bafc0247bbeef6101bdaccbd64 Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Tue, 30 Jun 2026 00:09:09 +0300 Subject: [PATCH 06/11] fix ci --- clang/lib/Frontend/CompilerInvocation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 56362e758a78b..41200a7626ab1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -5245,6 +5245,7 @@ std::string CompilerInvocation::computeContextHash() const { HBuilder.add(getLangOpts().ObjCRuntime); HBuilder.addRange(getLangOpts().CommentOpts.BlockCommandNames); + HBuilder.add(getLangOpts().CommentOpts.RetainCommentsFromSystemHeaders); // Extend the signature with the target options. HBuilder.add(getTargetOpts().Triple, getTargetOpts().CPU, >From f578ec8be32d5cd4558e2ae574f901a8cf165887 Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Wed, 1 Jul 2026 14:09:18 +0300 Subject: [PATCH 07/11] address reviews --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Parse/Parser.cpp | 11 +++-------- clang/lib/Sema/Sema.cpp | 4 ++-- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a1d07bdcef872..2235676602c27 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1135,7 +1135,7 @@ class Sema final : public SemaBase { /// Returns true if a comment at \p Loc should be retained in the AST /// (some consumer such as -Wdocumentation, -fparse-all-comments, code /// completion, or AST-file serialization may read it back). - bool shouldRetainCommentsFromLexer(SourceLocation Loc) const; + bool shouldRetainCommentsInAST(SourceLocation Loc) const; /// Retrieve the parser's current scope. /// diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index e8794ad9f44c9..6a21acd9dc4ef 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -74,12 +74,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) // destructor. initializePragmaHandlers(); - // Only install the comment handler when some consumer may read documentation - // comments back. - if (actions.shouldRetainCommentsFromLexer(SourceLocation())) { - CommentSemaHandler.reset(new ActionCommentHandler(actions)); - PP.addCommentHandler(CommentSemaHandler.get()); - } + CommentSemaHandler.reset(new ActionCommentHandler(actions)); + PP.addCommentHandler(CommentSemaHandler.get()); PP.setCodeCompletionHandler(*this); @@ -484,8 +480,7 @@ Parser::~Parser() { resetPragmaHandlers(); - if (CommentSemaHandler) - PP.removeCommentHandler(CommentSemaHandler.get()); + PP.removeCommentHandler(CommentSemaHandler.get()); PP.clearCodeCompletionHandler(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b8854beeda565..c0eb531335fdf 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2728,7 +2728,7 @@ LambdaScopeInfo *Sema::getCurGenericLambda() { return nullptr; } -bool Sema::shouldRetainCommentsFromLexer(SourceLocation Loc) const { +bool Sema::shouldRetainCommentsInAST(SourceLocation Loc) const { if (LangOpts.CommentOpts.ParseAllComments) return true; @@ -2757,7 +2757,7 @@ void Sema::ActOnComment(SourceRange Comment) { if (!LangOpts.CommentOpts.RetainCommentsFromSystemHeaders && SourceMgr.isInSystemHeader(Comment.getBegin())) return; - if (!shouldRetainCommentsFromLexer(Comment.getBegin())) + if (!shouldRetainCommentsInAST(Comment.getBegin())) return; RawComment RC(SourceMgr, Comment, LangOpts.CommentOpts, false); if (RC.isAlmostTrailingComment() || RC.hasUnsupportedSplice(SourceMgr)) { >From caa48b0276110a339c3b142c303a462c552f706f Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Wed, 1 Jul 2026 14:19:38 +0300 Subject: [PATCH 08/11] add a release note --- clang/docs/ReleaseNotes.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 9301745b9628e..312ce1905e749 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -285,6 +285,12 @@ latest release, please see the [Clang Web Site](https://clang.llvm.org) or the - Improved how Unicode characters are displayed in diagnostic messages. +- Clang no longer retains source comments in the AST when nothing will read them + back. Comments are now collected only when they may be consumed (e.g. with + ``-fparse-all-comments``, when ``-Wdocumentation`` is enabled, when emitting a + PCH/module, or during code completion), reducing memory overhead for typical + compilations. + - `-Wtautological-pointer-compare` and `-Wpointer-bool-conversion` now diagnose a reference to a function (e.g. of type `void (&)()`) compared against or converted to a null pointer, the same as a bare function name. >From 11d4c47f19a7cae3dfd86ef29a3900c054ac6553 Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Mon, 20 Jul 2026 06:50:29 +0300 Subject: [PATCH 09/11] add DiagnosticsEngine::areAllIgnored to check a whole warning group Co-authored-by: Erich Keane <[email protected]> --- clang/include/clang/Basic/Diagnostic.h | 10 ++ clang/include/clang/Basic/DiagnosticIDs.h | 6 + clang/lib/Basic/DiagnosticIDs.cpp | 196 ++++++++++++---------- 3 files changed, 128 insertions(+), 84 deletions(-) diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 66e79e3b4300b..95ea477502ea7 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -963,6 +963,16 @@ class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { diag::Severity::Ignored; } + bool areAllIgnored(StringRef Group, SourceLocation Loc) const { + llvm::SmallVector<diag::kind> diagsInGroup; + bool Failed = Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, + Group, diagsInGroup); + assert(!Failed && "Incorrect group name?"); + (void)Failed; + return Diags->getDiagnosticListHighestSeverity(diagsInGroup, Loc, *this) == + diag::Severity::Ignored; + } + /// Based on the way the client configured the DiagnosticsEngine /// object, classify the specified diagnostic ID into a Level, consumable by /// the DiagnosticConsumer. diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index 8e714efac46ae..cbd7677cd7108 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -514,6 +514,12 @@ class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const LLVM_READONLY; + /// Given a collection of diagnostic IDs, get the 'highest' severity of them + /// at the provided location for this DiagnosticsEngine. + diag::Severity getDiagnosticListHighestSeverity( + llvm::ArrayRef<diag::kind> DiagIDs, SourceLocation Loc, + const DiagnosticsEngine &Diag) const LLVM_READONLY; + Class getDiagClass(unsigned DiagID) const; /// Whether the diagnostic may leave the AST in a state where some diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index 92f96d1b9ad90..e9ce73863cb17 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -538,103 +538,131 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, diag::Severity DiagnosticIDs::getDiagnosticSeverity(unsigned DiagID, SourceLocation Loc, const DiagnosticsEngine &Diag) const { - bool IsCustomDiag = DiagnosticIDs::IsCustomDiag(DiagID); - assert(getDiagClass(DiagID) != CLASS_NOTE); - - // Specific non-error diagnostics may be mapped to various levels from ignored - // to error. Errors can only be mapped to fatal. - diag::Severity Result = diag::Severity::Fatal; + return getDiagnosticListHighestSeverity({DiagID}, Loc, Diag); +} - // Get the mapping information, or compute it lazily. +diag::Severity DiagnosticIDs::getDiagnosticListHighestSeverity( + llvm::ArrayRef<diag::kind> DiagIDs, SourceLocation Loc, + const DiagnosticsEngine &Diag) const { DiagnosticsEngine::DiagState *State = Diag.GetDiagStateForLoc(Loc); - DiagnosticMapping Mapping = State->getOrAddMapping((diag::kind)DiagID); - - // TODO: Can a null severity really get here? - if (Mapping.getSeverity() != diag::Severity()) - Result = Mapping.getSeverity(); - - // Upgrade ignored diagnostics if -Weverything is enabled. - if (State->EnableAllWarnings && Result == diag::Severity::Ignored && - !Mapping.isUser() && - (IsCustomDiag || getDiagClass(DiagID) != CLASS_REMARK)) - Result = diag::Severity::Warning; - - // Ignore -pedantic diagnostics inside __extension__ blocks. - // (The diagnostics controlled by -pedantic are the extension diagnostics - // that are not enabled by default.) - bool EnabledByDefault = false; - bool IsExtensionDiag = isExtensionDiag(DiagID, EnabledByDefault); - if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault) - return diag::Severity::Ignored; - - // For extension diagnostics that haven't been explicitly mapped, check if we - // should upgrade the diagnostic. Skip if the user explicitly suppressed it - // (e.g. -Wno-foo). - if (IsExtensionDiag && - !(Mapping.isUser() && Result == diag::Severity::Ignored)) { - if (Mapping.hasNoWarningAsError()) - Result = std::max(Result, - std::min(State->ExtBehavior, diag::Severity::Warning)); - else - Result = std::max(Result, State->ExtBehavior); - } - - // At this point, ignored errors can no longer be upgraded. - if (Result == diag::Severity::Ignored) - return Result; - // Honor -w: this disables all messages which are not Error/Fatal by - // default (disregarding attempts to upgrade severity from Warning to Error), - // as well as disabling all messages which are currently mapped to Warning - // (whether by default or downgraded from Error via e.g. -Wno-error or #pragma - // diagnostic.) - // FIXME: Should -w be ignored for custom warnings without a group? - if (State->IgnoreAllWarnings) { - if ((!IsCustomDiag || CustomDiagInfo->getDescription(DiagID).GetGroup()) && - (Result == diag::Severity::Warning || - (Result >= diag::Severity::Error && - !isDefaultMappingAsError((diag::kind)DiagID)))) + auto checkSingleDiag = [&](diag::kind DiagID) -> diag::Severity { + bool IsCustomDiag = DiagnosticIDs::IsCustomDiag(DiagID); + assert(getDiagClass(DiagID) != CLASS_NOTE); + + // Specific non-error diagnostics may be mapped to various levels from + // ignored to error. Errors can only be mapped to fatal. + diag::Severity Result = diag::Severity::Fatal; + + // Get the mapping information, or compute it lazily. + DiagnosticMapping Mapping = State->getOrAddMapping((diag::kind)DiagID); + + // TODO: Can a null severity really get here? + if (Mapping.getSeverity() != diag::Severity()) + Result = Mapping.getSeverity(); + + // Upgrade ignored diagnostics if -Weverything is enabled. + if (State->EnableAllWarnings && Result == diag::Severity::Ignored && + !Mapping.isUser() && + (IsCustomDiag || getDiagClass(DiagID) != CLASS_REMARK)) + Result = diag::Severity::Warning; + + // Ignore -pedantic diagnostics inside __extension__ blocks. + // (The diagnostics controlled by -pedantic are the extension diagnostics + // that are not enabled by default.) + bool EnabledByDefault = false; + bool IsExtensionDiag = isExtensionDiag(DiagID, EnabledByDefault); + if (Diag.AllExtensionsSilenced && IsExtensionDiag && !EnabledByDefault) return diag::Severity::Ignored; - } - // If -Werror is enabled, map warnings to errors unless explicitly disabled. - if (Result == diag::Severity::Warning) { - if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError()) + // For extension diagnostics that haven't been explicitly mapped, check if + // we should upgrade the diagnostic. Skip if the user explicitly + // suppressed it (e.g. -Wno-foo). + if (IsExtensionDiag && + !(Mapping.isUser() && Result == diag::Severity::Ignored)) { + if (Mapping.hasNoWarningAsError()) + Result = std::max( + Result, std::min(State->ExtBehavior, diag::Severity::Warning)); + else + Result = std::max(Result, State->ExtBehavior); + } + + // At this point, ignored errors can no longer be upgraded. + if (Result == diag::Severity::Ignored) + return Result; + + // Honor -w: this disables all messages which are not Error/Fatal by + // default (disregarding attempts to upgrade severity from Warning to + // Error), as well as disabling all messages which are currently mapped to + // Warning (whether by default or downgraded from Error via e.g. + // -Wno-error or #pragma diagnostic.) + // FIXME: Should -w be ignored for custom warnings without a group? + if (State->IgnoreAllWarnings) { + if ((!IsCustomDiag || + CustomDiagInfo->getDescription(DiagID).GetGroup()) && + (Result == diag::Severity::Warning || + (Result >= diag::Severity::Error && + !isDefaultMappingAsError((diag::kind)DiagID)))) + return diag::Severity::Ignored; + } + + // If -Werror is enabled, map warnings to errors unless explicitly + // disabled. + if (Result == diag::Severity::Warning) { + if (State->WarningsAsErrors && !Mapping.hasNoWarningAsError()) + Result = diag::Severity::Error; + } + + // If -Wfatal-errors is enabled, map errors to fatal unless explicitly + // disabled. + if (Result == diag::Severity::Error) { + if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) + Result = diag::Severity::Fatal; + } + + // If explicitly requested, map fatal errors to errors. + if (Result == diag::Severity::Fatal && + DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError) Result = diag::Severity::Error; - } - // If -Wfatal-errors is enabled, map errors to fatal unless explicitly - // disabled. - if (Result == diag::Severity::Error) { - if (State->ErrorsAsFatal && !Mapping.hasNoErrorAsFatal()) - Result = diag::Severity::Fatal; - } + // Rest of the mappings are only applicable for diagnostics associated + // with a SourceLocation, bail out early for others. + if (!Diag.hasSourceManager()) + return Result; + + // We check both the location-specific state and the ForceSystemWarnings + // override. In some cases (like template instantiations from system + // modules), the location-specific state might have suppression enabled, + // but the engine might have an override (e.g. + // AllowWarningInSystemHeaders) to show the warning. + if (State->SuppressSystemWarnings && !Diag.getForceSystemWarnings() && + shouldSuppressAsSystemWarning(DiagID, Loc, Diag)) { + return diag::Severity::Ignored; + } - // If explicitly requested, map fatal errors to errors. - if (Result == diag::Severity::Fatal && - DiagID != diag::fatal_too_many_errors && Diag.FatalsAsError) - Result = diag::Severity::Error; + // Clang-diagnostics pragmas always take precedence over suppression + // mapping. + if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc)) + return diag::Severity::Ignored; - // Rest of the mappings are only applicable for diagnostics associated with a - // SourceLocation, bail out early for others. - if (!Diag.hasSourceManager()) return Result; + }; - // We check both the location-specific state and the ForceSystemWarnings - // override. In some cases (like template instantiations from system modules), - // the location-specific state might have suppression enabled, but the - // engine might have an override (e.g. AllowWarningInSystemHeaders) to show - // the warning. - if (State->SuppressSystemWarnings && !Diag.getForceSystemWarnings() && - shouldSuppressAsSystemWarning(DiagID, Loc, Diag)) { - return diag::Severity::Ignored; + diag::Severity CompositeResult = diag::Severity::Ignored; + for (diag::kind DiagID : DiagIDs) { + CompositeResult = std::max(CompositeResult, checkSingleDiag(DiagID)); + + // If we already hit 'fatal', we can't get any higher! So just return that. + // We could potentially short-cut this by taking a parameter for "return + // first greater than", but since our uses of this are fairly small, and + // that only optimizes for the "we are about to do something expensive + // anyway" variant (that is, when everything is NOT ignored), it doesn't + // seem particularly valuable. + if (CompositeResult == diag::Severity::Fatal) + break; } - // Clang-diagnostics pragmas always take precedence over suppression mapping. - if (!Mapping.isPragma() && Diag.isSuppressedViaMapping(DiagID, Loc)) - return diag::Severity::Ignored; - - return Result; + return CompositeResult; } bool DiagnosticIDs::shouldSuppressAsSystemWarning( >From 69d517df6d4703d05fdbb5a7468afa84fb7bda17 Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Mon, 20 Jul 2026 06:50:29 +0300 Subject: [PATCH 10/11] use areAllIgnored to check the whole -Wdocumentation warning groups --- clang/lib/Sema/Sema.cpp | 12 ++++++------ clang/lib/Sema/SemaDecl.cpp | 7 ++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index c0eb531335fdf..a2aadebb7de34 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -24,7 +24,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/DarwinSDKInfo.h" -#include "clang/Basic/DiagnosticComment.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -32,7 +31,6 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Lex/PreprocessorOptions.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ExternalSemaSource.h" @@ -2744,10 +2742,12 @@ bool Sema::shouldRetainCommentsInAST(SourceLocation Loc) const { if (PP.isCodeCompletionEnabled()) return true; - // Keep the comment if -Wdocumentation is enabled at its location (checking - // the location handles warnings turned on by `#pragma clang diagnostic`). - if (!Diags.isIgnored(diag::warn_doc_param_not_found, Loc) || - !Diags.isIgnored(diag::warn_unknown_comment_command_name, Loc)) + // Keep the comment if any of the -Wdocumentation warnings is enabled at + // its location (checking the location handles warnings turned on by + // `#pragma clang diagnostic`). -Wdocumentation-pedantic is checked + // separately because it is not a subgroup of -Wdocumentation. + if (!Diags.areAllIgnored("documentation", Loc) || + !Diags.areAllIgnored("documentation-pedantic", Loc)) return true; return false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9b2efd96cb62d..4629d9b3c636f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -30,7 +30,6 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" -#include "clang/Basic/DiagnosticComment.h" #include "clang/Basic/HLSLRuntime.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -15620,10 +15619,8 @@ void Sema::ActOnDocumentableDecls(ArrayRef<Decl *> Group) { if (Group.empty() || !Group[0]) return; - if (Diags.isIgnored(diag::warn_doc_param_not_found, - Group[0]->getLocation()) && - Diags.isIgnored(diag::warn_unknown_comment_command_name, - Group[0]->getLocation())) + if (Diags.areAllIgnored("documentation", Group[0]->getLocation()) && + Diags.areAllIgnored("documentation-pedantic", Group[0]->getLocation())) return; if (Group.size() >= 2) { >From a08b2ec9d19a8726c022adc0fc688af44029599e Mon Sep 17 00:00:00 2001 From: Anonmiraj <[email protected]> Date: Mon, 20 Jul 2026 07:56:37 +0300 Subject: [PATCH 11/11] add tests --- clang/test/AST/ast-dump-comment-retention.cpp | 28 ++++++++++++++ .../warn-documentation-comment-retention.cpp | 38 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 clang/test/AST/ast-dump-comment-retention.cpp create mode 100644 clang/test/Sema/warn-documentation-comment-retention.cpp diff --git a/clang/test/AST/ast-dump-comment-retention.cpp b/clang/test/AST/ast-dump-comment-retention.cpp new file mode 100644 index 0000000000000..e2a68e2f3221d --- /dev/null +++ b/clang/test/AST/ast-dump-comment-retention.cpp @@ -0,0 +1,28 @@ +// Comments are only collected into the AST when a consumer may read them back +// (see Sema::shouldRetainCommentsInAST). -ast-dump is such a consumer: it +// force-enables comment retention, so documentation comments remain visible in +// its output even without -Wdocumentation. An ordinary comment is only turned +// into an AST comment node when -fparse-all-comments is passed. + +// RUN: %clang_cc1 -ast-dump -ast-dump-filter Test %s \ +// RUN: | FileCheck -strict-whitespace %s --check-prefixes=CHECK,DEFAULT +// RUN: %clang_cc1 -fparse-all-comments -ast-dump -ast-dump-filter Test %s \ +// RUN: | FileCheck -strict-whitespace %s --check-prefixes=CHECK,ALL + +/// Doc +int Test_DocComment; +// A documentation comment is retained for -ast-dump in both modes. +// CHECK: VarDecl{{.*}}Test_DocComment +// CHECK-NEXT: FullComment +// CHECK-NEXT: ParagraphComment +// CHECK-NEXT: TextComment{{.*}} Text=" Doc" + +// Ordinary +int Test_OrdinaryComment; +// An ordinary comment becomes an AST comment node only with +// -fparse-all-comments; by default it is dropped. +// CHECK: VarDecl{{.*}}Test_OrdinaryComment +// ALL-NEXT: FullComment +// ALL-NEXT: ParagraphComment +// ALL-NEXT: TextComment{{.*}} Text=" Ordinary" +// DEFAULT-NOT: FullComment diff --git a/clang/test/Sema/warn-documentation-comment-retention.cpp b/clang/test/Sema/warn-documentation-comment-retention.cpp new file mode 100644 index 0000000000000..5d7a50b0bb970 --- /dev/null +++ b/clang/test/Sema/warn-documentation-comment-retention.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// The comment-retention optimization (Sema::shouldRetainCommentsInAST) must +// still parse a documentation comment when -Wdocumentation is enabled at the +// comment's location -- including when it is turned on by a #pragma clang +// diagnostic rather than on the command line. The check is done at the +// comment's location precisely so pragma regions are honored. + +/// \returns Aaa +void outside(); +// -Wdocumentation is off at this location, so the comment is not checked and +// no diagnostic is produced. -verify fails on any unexpected diagnostic, so +// this line asserts the comment is *not* diagnosed here. + +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wdocumentation" +/// \returns Aaa +void inside(); +// expected-warning@-2 {{'\returns' command used in a comment that is attached to a function returning void}} +#pragma clang diagnostic pop + +// Any warning in the -Wdocumentation group must keep the comment, not just a +// hard-coded subset: -Wdocumentation-html is a subgroup of -Wdocumentation. +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wdocumentation-html" +/// Aaa <br></br> +void html_inside(); +// expected-warning@-2 {{HTML end tag 'br' is forbidden}} +#pragma clang diagnostic pop + +// -Wdocumentation-unknown-command is under -Wdocumentation-pedantic, which is +// not a subgroup of -Wdocumentation and must be checked separately. +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wdocumentation-unknown-command" +/// \unknowncommand Aaa +void unknown_inside(); +// expected-warning@-2 {{unknown command tag name}} +#pragma clang diagnostic pop _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
