Skip to content

[clang][Sema] Suggest/Hint Standard Library Include File #146227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Mr-Anyone
Copy link
Contributor

Clang now tries to suggest and hint standard library include file by emitting the following.

    4 |     std::unordered_map<std::string, std::string> map;
      |          ^~~~~~~~~~~~~
main.cpp:4:10: note: maybe try to include <unordered_map>; 'std::unordered_map' is defined in <unordered_map>
main.cpp:4:10: note: 'std::unordered_map' is a c++11 feature
main.cpp:4:42: note: maybe try to include <string>; 'std::string' is defined in <string>

This works for both C and C++.

fixes #120388

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules labels Jun 28, 2025
@llvmbot
Copy link
Member

llvmbot commented Jun 28, 2025

@llvm/pr-subscribers-clang

Author: Vincent (Mr-Anyone)

Changes

Clang now tries to suggest and hint standard library include file by emitting the following.

    4 |     std::unordered_map&lt;std::string, std::string&gt; map;
      |          ^~~~~~~~~~~~~
main.cpp:4:10: note: maybe try to include &lt;unordered_map&gt;; 'std::unordered_map' is defined in &lt;unordered_map&gt;
main.cpp:4:10: note: 'std::unordered_map' is a c++11 feature
main.cpp:4:42: note: maybe try to include &lt;string&gt;; 'std::string' is defined in &lt;string&gt;

This works for both C and C++.

fixes #120388


Patch is 644.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146227.diff

26 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/include/clang/Sema/Sema.h (+10)
  • (modified) clang/include/clang/Tooling/Inclusions/StandardLibrary.h (+22)
  • (modified) clang/lib/Parse/ParseExprCXX.cpp (+14)
  • (modified) clang/lib/Sema/CMakeLists.txt (+1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+49)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+6)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc (+429-697)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp (+55-5)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc (-5)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc (+2014-2140)
  • (modified) clang/test/Headers/stddef.c (+40-6)
  • (modified) clang/test/Headers/stddefneeds.c (+67-13)
  • (modified) clang/test/Headers/stddefneeds.cpp (+10-10)
  • (modified) clang/test/Modules/implicit-declared-allocation-functions.cppm (+12-6)
  • (modified) clang/test/Modules/macro-reexport.cpp (+3-3)
  • (modified) clang/test/Modules/stddef.cpp (+2-2)
  • (modified) clang/test/Sema/MicrosoftCompatibility.c (+1-1)
  • (modified) clang/test/Sema/builtin-setjmp.c (+5-3)
  • (modified) clang/test/Sema/c23-delayed-typo-correction-crashes.c (+2-1)
  • (modified) clang/test/Sema/implicit-builtin-decl.c (+2-1)
  • (added) clang/test/Sema/include-suggestion.c (+5)
  • (modified) clang/test/SemaCXX/constructor-initializer.cpp (+1-1)
  • (added) clang/test/SemaCXX/include-suggestions-cxx.cpp (+2458)
  • (modified) clang/test/SemaCXX/no-implicit-builtin-decls.cpp (+1-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 96477ef6ddc9a..b38dafb06e3ca 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -470,6 +470,7 @@ Improvements to Clang's diagnostics
   diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
   a bunch of HLSL types being printed as their C++ equivalents.
 - Clang now consistently quotes expressions in diagnostics.
+- Clang now suggest standard library include path and its associated C++ or C language version.
 - When printing types for diagnostics, clang now doesn't suppress the scopes of
   template arguments contained within nested names.
 - The ``-Wshift-bool`` warning has been added to warn about shifting a boolean. (#GH28334)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f2f2152b8bbbe..96f444544291d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5978,6 +5978,10 @@ def err_template_expansion_into_fixed_list : Error<
   "template|concept}0">;
 def note_parameter_type : Note<
   "parameter of type %0 is declared here">;
+def note_standard_lib_include_suggestion : Note<
+  "maybe try to include %0; '%1' is defined in %0">;
+def note_standard_lib_version : Note<
+  "'%0' is a %1 feature">;
 
 // C++11 Variadic Templates
 def err_template_param_pack_default_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9397546c8fc5d..f4c22cc255876 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3611,6 +3611,16 @@ class Sema final : public SemaBase {
                                ParsedType &SuggestedType,
                                bool IsTemplateName = false);
 
+  // Try to suggest the missing standard library include files
+  //
+  // \param SymbolName the symbol name like 'cout'
+  // \param SourceLocation the location of the note being emitted
+  // \param Namespace the namespace that must end with ::, so like 'std::'
+  void NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                            StringRef Namespace);
+  void NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                            const CXXScopeSpec *SS);
+
   /// Attempt to behave like MSVC in situations where lookup of an unqualified
   /// type name has failed in a dependent context. In these situations, we
   /// automatically form a DependentTypeName that will retry lookup in a related
diff --git a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
index 147f505ade058..42bbb5b3f0d8c 100644
--- a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
+++ b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
@@ -29,6 +29,27 @@ class NamespaceDecl;
 class DeclContext;
 namespace tooling {
 namespace stdlib {
+enum Version {
+  Unknown,
+
+  // c++ versions
+  CPlusPlusStart,
+  CPlusPlus11,
+  CPlusPlus14,
+  CPlusPlus17,
+  CPlusPlus20,
+  CPlusPlus23,
+  CPlusPlus26,
+  CPlusPlusEnd,
+
+  // c version
+  CStart,
+  C99,
+  C11,
+  CEnd
+};
+
+llvm::StringRef GetAsString(Version Ver);
 
 class Symbol;
 enum class Lang { C = 0, CXX, LastValue = CXX };
@@ -85,6 +106,7 @@ class Symbol {
   std::optional<Header> header() const;
   // Some symbols may be provided by multiple headers.
   llvm::SmallVector<Header> headers() const;
+  Version version() const;
 
 private:
   Symbol(unsigned ID, Lang Language) : ID(ID), Language(Language) {}
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 1ea0cf52933f6..9de0e9ca74c6f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -226,6 +226,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     HasScopeSpecifier = true;
   }
 
+  // If `FailedNestedNameBuilding` is true, attempt to suggest the standard
+  // include file corresponding to the current `FullNamespace` and symbol.
+  std::string FullNamespace = "";
+  bool FailedNesatedNameBuilding = false;
+
   // Preferred type might change when parsing qualifiers, we need the original.
   auto SavedType = PreferredType;
   while (true) {
@@ -454,6 +459,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
       // We have an identifier followed by a '::'. Lookup this name
       // as the name in a nested-name-specifier.
       Token Identifier = Tok;
+      FullNamespace += Identifier.getIdentifierInfo()->getName();
+      FullNamespace += "::";
+
       SourceLocation IdLoc = ConsumeToken();
       assert(Tok.isOneOf(tok::coloncolon, tok::colon) &&
              "NextToken() not working properly!");
@@ -465,6 +473,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
       if (Actions.ActOnCXXNestedNameSpecifier(
               getCurScope(), IdInfo, EnteringContext, SS, CorrectionFlagPtr,
               OnlyNamespace)) {
+        FailedNesatedNameBuilding = true;
         // Identifier is not recognized as a nested name, but we can have
         // mistyped '::' instead of ':'.
         if (CorrectionFlagPtr && IsCorrectedToColon) {
@@ -554,6 +563,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     break;
   }
 
+  if (FailedNesatedNameBuilding && Tok.getKind() == tok::identifier) {
+    Actions.NoteStandardIncludes(Tok.getIdentifierInfo()->getName(),
+                                 Tok.getLocation(), FullNamespace);
+  }
+
   // Even if we didn't see any pieces of a nested-name-specifier, we
   // still check whether there is a tilde in this position, which
   // indicates a potential pseudo-destructor.
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 51e0ee10b080b..ff4f583bdd9bf 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -115,4 +115,5 @@ add_clang_library(clangSema
   clangEdit
   clangLex
   clangSupport
+  clangToolingInclusionsStdlib
   )
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e1cccf068b5aa..7d659a6d06f93 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -58,10 +58,12 @@
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/Template.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/TargetParser/Triple.h"
@@ -805,6 +807,52 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
     assert(SS && SS->isInvalid() &&
            "Invalid scope specifier has already been diagnosed");
   }
+
+  // don't note standard include files for OpenCL and Objective C
+  if ((getLangOpts().CPlusPlus || getLangOpts().C99) && !getLangOpts().OpenCL &&
+      !getLangOpts().ObjC)
+    NoteStandardIncludes(II->getName(), IILoc, SS);
+}
+
+void Sema::NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                                StringRef Namespace) {
+  using clang::tooling::stdlib::Lang;
+
+  llvm::StringRef HeaderName = "";
+  tooling::stdlib::Lang LangOption = tooling::stdlib::Lang::C;
+  if (getLangOpts().CPlusPlus)
+    LangOption = clang::tooling::stdlib::Lang::CXX;
+
+  if (auto StdSym =
+          tooling::stdlib::Symbol::named(Namespace, SymbolName, LangOption)) {
+    if (auto Header = StdSym->header()) {
+      HeaderName = Header->name();
+      Diag(IILoc, diag::note_standard_lib_include_suggestion)
+          << HeaderName << (Namespace + SymbolName).str();
+
+      // Noting the C/C++ version as well
+      if (StdSym->version() != tooling::stdlib::Unknown) {
+        llvm::StringRef CPlusPlusVersion =
+            tooling::stdlib::GetAsString(StdSym->version());
+
+        Diag(IILoc, diag::note_standard_lib_version)
+            << (Namespace + SymbolName).str() << CPlusPlusVersion;
+      }
+    }
+  }
+}
+
+void Sema::NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                                const CXXScopeSpec *SS) {
+  std::string Namespace = "";
+  if (SS) {
+    llvm::raw_string_ostream Stream(Namespace);
+    if (SS->isValid())
+      SS->getScopeRep()->dump(Stream);
+    Stream.flush();
+  }
+
+  NoteStandardIncludes(SymbolName, IILoc, Namespace);
 }
 
 /// Determine whether the given result set contains either a type name
@@ -16784,6 +16832,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
   }
 
   Diag(Loc, diag_id) << &II;
+  NoteStandardIncludes(II.getName(), Loc, "");
   if (Corrected) {
     // If the correction is going to suggest an implicitly defined function,
     // skip the correction as not being a particularly good idea.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index fc2819458a4ff..9015b70deb5d1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2660,11 +2660,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
   if (!SS.isEmpty()) {
     Diag(R.getNameLoc(), diag::err_no_member)
         << Name << computeDeclContext(SS, false) << NameRange;
+    NoteStandardIncludes(Name.getAsString(), R.getNameLoc(), &SS);
     return true;
   }
 
   // Give up, we can't recover.
   Diag(R.getNameLoc(), diagnostic) << Name << NameRange;
+
+  // don't note standard include files for OpenCL and Objective C
+  if ((getLangOpts().CPlusPlus || getLangOpts().C99) && !getLangOpts().OpenCL &&
+      !getLangOpts().ObjC)
+    NoteStandardIncludes(Name.getAsString(), R.getNameLoc(), /*Namespace=*/"");
   return true;
 }
 
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..b3a1921f3c74b 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -6,246 +6,44 @@
 // This file was generated automatically by
 // clang/tools/include-mapping/gen_std.py, DO NOT EDIT!
 //
-// Generated from cppreference offline HTML book (modified on 2018-10-28).
+// Generated from cppreference offline HTML book (modified on 2025-02-10).
 //===----------------------------------------------------------------------===//
 
-SYMBOL(ATOMIC_BOOL_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR16_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR32_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_FLAG_INIT, None, <stdatomic.h>)
-SYMBOL(ATOMIC_INT_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_LLONG_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_LONG_LOGK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_POINTER_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_SHORT_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_VAR_INIT, None, <stdatomic.h>)
-SYMBOL(ATOMIC_WCHAR_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(BUFSIZ, None, <stdio.h>)
-SYMBOL(CHAR_BIT, None, <limits.h>)
-SYMBOL(CHAR_MAX, None, <limits.h>)
-SYMBOL(CHAR_MIN, None, <limits.h>)
-SYMBOL(CLOCKS_PER_SEC, None, <time.h>)
-SYMBOL(CMPLX, None, <complex.h>)
-SYMBOL(CMPLXF, None, <complex.h>)
-SYMBOL(CMPLXL, None, <complex.h>)
-SYMBOL(DBL_DECIMAL_DIG, None, <float.h>)
-SYMBOL(DBL_DIG, None, <float.h>)
-SYMBOL(DBL_EPSILON, None, <float.h>)
-SYMBOL(DBL_HAS_SUBNORM, None, <float.h>)
-SYMBOL(DBL_MANT_DIG, None, <float.h>)
-SYMBOL(DBL_MAX, None, <float.h>)
-SYMBOL(DBL_MAX_10_EXP, None, <float.h>)
-SYMBOL(DBL_MAX_EXP, None, <float.h>)
-SYMBOL(DBL_MIN, None, <float.h>)
-SYMBOL(DBL_MIN_10_EXP, None, <float.h>)
-SYMBOL(DBL_MIN_EXP, None, <float.h>)
-SYMBOL(DBL_TRUE_MIN, None, <float.h>)
-SYMBOL(DECIMAL_DIG, None, <float.h>)
-SYMBOL(EDOM, None, <errno.h>)
-SYMBOL(EILSEQ, None, <errno.h>)
-SYMBOL(EOF, None, <stdio.h>)
-SYMBOL(ERANGE, None, <errno.h>)
-SYMBOL(EXIT_FAILURE, None, <stdlib.h>)
-SYMBOL(EXIT_SUCCESS, None, <stdlib.h>)
-SYMBOL(FE_ALL_EXCEPT, None, <fenv.h>)
-SYMBOL(FE_DFL_ENV, None, <fenv.h>)
-SYMBOL(FE_DIVBYZERO, None, <fenv.h>)
-SYMBOL(FE_DOWNWARD, None, <fenv.h>)
-SYMBOL(FE_INEXACT, None, <fenv.h>)
-SYMBOL(FE_INVALID, None, <fenv.h>)
-SYMBOL(FE_OVERFLOW, None, <fenv.h>)
-SYMBOL(FE_TONEAREST, None, <fenv.h>)
-SYMBOL(FE_TOWARDZERO, None, <fenv.h>)
-SYMBOL(FE_UNDERFLOW, None, <fenv.h>)
-SYMBOL(FE_UPWARD, None, <fenv.h>)
 SYMBOL(FILE, None, <stdio.h>)
-SYMBOL(FILENAME_MAX, None, <stdio.h>)
-SYMBOL(FLT_DECIMAL_DIG, None, <float.h>)
-SYMBOL(FLT_DIG, None, <float.h>)
-SYMBOL(FLT_EPSILON, None, <float.h>)
-SYMBOL(FLT_EVAL_METHOD, None, <float.h>)
-SYMBOL(FLT_HAS_SUBNORM, None, <float.h>)
-SYMBOL(FLT_MANT_DIG, None, <float.h>)
-SYMBOL(FLT_MAX, None, <float.h>)
-SYMBOL(FLT_MAX_10_EXP, None, <float.h>)
-SYMBOL(FLT_MAX_EXP, None, <float.h>)
-SYMBOL(FLT_MIN, None, <float.h>)
-SYMBOL(FLT_MIN_10_EXP, None, <float.h>)
-SYMBOL(FLT_MIN_EXP, None, <float.h>)
-SYMBOL(FLT_RADIX, None, <float.h>)
-SYMBOL(FLT_ROUNDS, None, <float.h>)
-SYMBOL(FLT_TRUE_MIN, None, <float.h>)
-SYMBOL(FOPEN_MAX, None, <stdio.h>)
-SYMBOL(FP_INFINITE, None, <math.h>)
-SYMBOL(FP_NAN, None, <math.h>)
-SYMBOL(FP_NORNAL, None, <math.h>)
-SYMBOL(FP_SUBNORMAL, None, <math.h>)
-SYMBOL(FP_ZERO, None, <math.h>)
-SYMBOL(HUGE_VAL, None, <math.h>)
-SYMBOL(HUGE_VALF, None, <math.h>)
-SYMBOL(HUGE_VALL, None, <math.h>)
-SYMBOL(I, None, <complex.h>)
-SYMBOL(INFINITY, None, <math.h>)
-SYMBOL(INT16_MAX, None, <stdint.h>)
-SYMBOL(INT16_MIN, None, <stdint.h>)
-SYMBOL(INT32_MAX, None, <stdint.h>)
-SYMBOL(INT32_MIN, None, <stdint.h>)
-SYMBOL(INT64_MAX, None, <stdint.h>)
-SYMBOL(INT64_MIN, None, <stdint.h>)
-SYMBOL(INT8_MAX, None, <stdint.h>)
-SYMBOL(INT8_MIN, None, <stdint.h>)
-SYMBOL(INTMAX_MAX, None, <stdint.h>)
-SYMBOL(INTMAX_MIN, None, <stdint.h>)
-SYMBOL(INTPTR_MAX, None, <stdint.h>)
-SYMBOL(INTPTR_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST16_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST16_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST32_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST32_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST64_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST64_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST8_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST8_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST16_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST16_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST32_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST32_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST64_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST64_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST8_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST8_MIN, None, <stdint.h>)
-SYMBOL(INT_MAX, None, <limits.h>)
-SYMBOL(INT_MIN, None, <limits.h>)
-SYMBOL(LC_ALL, None, <locale.h>)
-SYMBOL(LC_COLLATE, None, <locale.h>)
-SYMBOL(LC_CTYPE, None, <locale.h>)
-SYMBOL(LC_MONETARY, None, <locale.h>)
-SYMBOL(LC_NUMERIC, None, <locale.h>)
-SYMBOL(LC_TIME, None, <locale.h>)
-SYMBOL(LDBL_DECIMAL_DIG, None, <float.h>)
-SYMBOL(LDBL_DIG, None, <float.h>)
-SYMBOL(LDBL_EPSILON, None, <float.h>)
-SYMBOL(LDBL_HAS_SUBNORM, None, <float.h>)
-SYMBOL(LDBL_MANT_DIG, None, <float.h>)
-SYMBOL(LDBL_MAX, None, <float.h>)
-SYMBOL(LDBL_MAX_10_EXP, None, <float.h>)
-SYMBOL(LDBL_MAX_EXP, None, <float.h>)
-SYMBOL(LDBL_MIN, None, <float.h>)
-SYMBOL(LDBL_MIN_10_EXP, None, <float.h>)
-SYMBOL(LDBL_MIN_EXP, None, <float.h>)
-SYMBOL(LDBL_TRUE_MIN, None, <float.h>)
-SYMBOL(LLONG_MAX, None, <limits.h>)
-SYMBOL(LLONG_MIN, None, <limits.h>)
-SYMBOL(LONG_MAX, None, <limits.h>)
-SYMBOL(LONG_MIN, None, <limits.h>)
-SYMBOL(L_tmpnam, None, <stdio.h>)
-SYMBOL(L_tmpnam_s, None, <stdio.h>)
-SYMBOL(MATH_ERREXCEPT, None, <math.h>)
-SYMBOL(MATH_ERRNO, None, <math.h>)
-SYMBOL(MB_CUR_MAX, None, <stdlib.h>)
-SYMBOL(MB_LEN_MAX, None, <limits.h>)
-SYMBOL(NAN, None, <math.h>)
-SYMBOL(ONCE_FLAG_INIT, None, <threads.h>)
-SYMBOL(PTRDIFF_MAX, None, <stdint.h>)
-SYMBOL(PTRDIFF_MIN, None, <stdint.h>)
-SYMBOL(RAND_MAX, None, <stdlib.h>)
-SYMBOL(RSIZE_MAX, None, <stdint.h>)
-SYMBOL(SCHAR_MAX, None, <limits.h>)
-SYMBOL(SCHAR_MIN, None, <limits.h>)
-SYMBOL(SEEK_CUR, None, <stdio.h>)
-SYMBOL(SEEK_END, None, <stdio.h>)
-SYMBOL(SEEK_SET, None, <stdio.h>)
-SYMBOL(SHRT_MAX, None, <limits.h>)
-SYMBOL(SHRT_MIN, None, <limits.h>)
-SYMBOL(SIGABRT, None, <signal.h>)
-SYMBOL(SIGFPE, None, <signal.h>)
-SYMBOL(SIGILL, None, <signal.h>)
-SYMBOL(SIGINT, None, <signal.h>)
-SYMBOL(SIGSEGV, None, <signal.h>)
-SYMBOL(SIGTERM, None, <signal.h>)
-SYMBOL(SIG_ATOMIC_MAX, None, <stdint.h>)
-SYMBOL(SIG_ATOMIC_MIN, None, <stdint.h>)
-SYMBOL(SIG_DFL, None, <signal.h>)
-SYMBOL(SIG_ERR, None, <signal.h>)
-SYMBOL(SIG_IGN, None, <signal.h>)
-SYMBOL(SIZE_MAX, None, <stdint.h>)
-SYMBOL(TIME_UTC, None, <time.h>)
-SYMBOL(TMP_MAX, None, <stdio.h>)
-SYMBOL(TMP_MAX_S, None, <stdio.h>)
-SYMBOL(TSS_DTOR_ITERATIONS, None, <threads.h>)
-SYMBOL(UCHAR_MAX, None, <limits.h>)
-SYMBOL(UINT16_MAX, None, <stdint.h>)
-SYMBOL(UINT32_MAX, None, <stdint.h>)
-SYMBOL(UINT64_MAX, None, <stdint.h>)
-SYMBOL(UINT8_MAX, None, <stdint.h>)
-SYMBOL(UINTMAX_MAX, None, <stdint.h>)
-SYMBOL(UINTPTR_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST16_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST32_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST64_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST8_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST16_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST32_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST64_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST8_MAX, None, <stdint.h>)
-SYMBOL(UINT_MAX, None, <limits.h>)
-SYMBOL(ULLONG_MAX, None, <limits.h>)
-SYMBOL(ULONG_MAX, None, <limits.h>)
-SYMBOL(USHRT_MAX, None, <limits.h>)
-SYMBOL(WCHAR_MAX, None, <wchar.h>)
-SYMBOL(WCHAR_MIN, None, <wchar.h>)
-SYMBOL(WEOF, None, <wchar.h>)
-SYMBOL(WINT_MAX, None, <stdint.h>)
-SYMBOL(WINT_MIN, None, <stdint.h>)
-SYMBOL(_Complex_I, None, <complex.h>)
-SYMBOL(_IOFBF, None, <stdio.h>)
-SYMBOL(_IOLBF, None, <stdio.h>)
-SYMBOL(_IONBF, None, <stdio.h>)
-SYMBOL(_Imaginary_I, None, <complex.h>)
-SYMBOL(__alignas_is_defined, None, <stdalign.h>)
-SYMBOL(__alignof_is_defined, None, <stdalign.h>)
-SYMBOL(abort_handler_s, None, <stdlib.h>)
+SYMBOL_VERSION(_Exit, None, <stdlib.h>, c99)
+SYMBOL(abort, None, <stdlib.h>)
+SYMBOL_VERSION(abort_handler_s, None, <stdlib.h>, c11)
 SYMBOL(abs, None, <stdlib.h>)
 SYMBOL(acos, None, <math.h>)
-SYMBOL(acosf, None, <math.h>)
-SYMBOL(acosh, None, <math.h>)
-SYMBOL(acoshf, None, <math.h>)
-SYMBOL(acoshl, None, <math.h>)
-SYMBOL(acosl, None, <math.h>)
-SYMBOL(alignas, None, <stdalign.h>)
-SYMBOL(aligned_alloc, None, <stdlib.h>)
-SYMBOL(alignof, None, <stdalign.h>)
-SYMBOL(and, None, <iso646.h>)
-SYMBOL(and_eq, None, <iso646.h>)
+SYMBOL_VERSION(acosf, None, <math.h>, c99)
+SYMBOL_VERSION(acosh, None, <math.h>, c99)
+SYMBOL_VERSION(acoshf, None, <math.h>, c99)
+SYMBOL_VERSION(acoshl, None, <math.h>, c99)
+SYMBOL_VERSION(acosl, None, <math.h>, c99)
+SYMBOL_VERSION(aligned_alloc, None, <stdlib.h>, c11)
 SYMBOL(asctime, None, <time.h>)
-SYMBOL(asctime_s, None, <time.h>)
+SYMBOL_VERSION(asctime_s, None, <time.h>, c11)
 SYMBOL(asin, None, <math.h>)
-SYMBOL(asinf, None, <math.h>)
-SYMBOL(asinh, None, <math.h>)
-SYMBOL(asinhf, None, <math.h>)
-SYMBOL(asinhl, None, <math.h>)
-SYMBOL(asinl, None, <math.h>)
-SYMBOL(assert, None, <assert.h>)
-SYMBOL(at_quick_exit, None, <stdlib.h>)
+SYMBOL_VERSION(asinf, None, <math.h>, c99)
+SYMBOL_VERSION(asinh, None, <math.h>, c99)
+SYMBOL_VERSION(asinhf, None, <math.h>, c99)
+SYMBOL_VERSION(asinhl, None, <math.h>, c99)
+SYMBOL_VERSION(asinl, None, <math.h>, c99)
+SYMBOL_VERSION(at_quick_exit, None, <stdlib.h>, c11)
 SYMBOL(atan, None, <math.h>)
 SYMBOL(atan2, None, <math.h>)
-SYMBOL(atan2f, None, <math.h>)
-SYMBOL(atan2l, None, <math.h>)
-SYMBOL(atanf, None, <math.h>)
-SYMBOL(atanh, None, <math.h>)
-SYMBOL(atanhf, None, <math.h>)
-SYMBOL(atanhl, None, <math.h>)
-SYMBOL(atanl, None, <math.h>)
+SYMBOL_VERSION(atan2f, None, <math.h>, c99)
+SYMBOL_VERSION(atan2l, None, <math.h>, c99)
+SYMBOL_VERSION(atanf, None, <math.h>, c99)
+SYMBOL_VERSION(atanh, None, <math.h>, c99)
+SYMBOL_VERSION(atanhf, None, <math.h>, c99)
+SYMBOL_VERSION(atanhl, None, <math.h>, c99)
+SYMBOL_VERSION(atanl, None, <math.h>, c99)
 SYMBOL(atexit, None, <stdlib.h>)
 SYMBOL(atof, None, <stdlib.h>)
 SYMBOL(atoi, None, <stdlib.h>)
 SYMBOL(atol, None, <stdlib.h>)
-SYMBOL(atoll, None, <stdlib.h>)
-SYMBOL(atomic_bool, None, <stdatomic.h>)
-SYMBOL(atomic_char, None, <stdatomic.h>)
-SYMBOL(atomic_char16_t, None, <stdatomic.h>)
-SYMBOL(atomic_char32_t, None, <stdatomic.h>)
+SYMBOL_VERSION(atoll,...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jun 28, 2025

@llvm/pr-subscribers-clang-modules

Author: Vincent (Mr-Anyone)

Changes

Clang now tries to suggest and hint standard library include file by emitting the following.

    4 |     std::unordered_map&lt;std::string, std::string&gt; map;
      |          ^~~~~~~~~~~~~
main.cpp:4:10: note: maybe try to include &lt;unordered_map&gt;; 'std::unordered_map' is defined in &lt;unordered_map&gt;
main.cpp:4:10: note: 'std::unordered_map' is a c++11 feature
main.cpp:4:42: note: maybe try to include &lt;string&gt;; 'std::string' is defined in &lt;string&gt;

This works for both C and C++.

fixes #120388


Patch is 644.43 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/146227.diff

26 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
  • (modified) clang/include/clang/Sema/Sema.h (+10)
  • (modified) clang/include/clang/Tooling/Inclusions/StandardLibrary.h (+22)
  • (modified) clang/lib/Parse/ParseExprCXX.cpp (+14)
  • (modified) clang/lib/Sema/CMakeLists.txt (+1)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+49)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+6)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc (+429-697)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StandardLibrary.cpp (+55-5)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StdSpecialSymbolMap.inc (-5)
  • (modified) clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc (+2014-2140)
  • (modified) clang/test/Headers/stddef.c (+40-6)
  • (modified) clang/test/Headers/stddefneeds.c (+67-13)
  • (modified) clang/test/Headers/stddefneeds.cpp (+10-10)
  • (modified) clang/test/Modules/implicit-declared-allocation-functions.cppm (+12-6)
  • (modified) clang/test/Modules/macro-reexport.cpp (+3-3)
  • (modified) clang/test/Modules/stddef.cpp (+2-2)
  • (modified) clang/test/Sema/MicrosoftCompatibility.c (+1-1)
  • (modified) clang/test/Sema/builtin-setjmp.c (+5-3)
  • (modified) clang/test/Sema/c23-delayed-typo-correction-crashes.c (+2-1)
  • (modified) clang/test/Sema/implicit-builtin-decl.c (+2-1)
  • (added) clang/test/Sema/include-suggestion.c (+5)
  • (modified) clang/test/SemaCXX/constructor-initializer.cpp (+1-1)
  • (added) clang/test/SemaCXX/include-suggestions-cxx.cpp (+2458)
  • (modified) clang/test/SemaCXX/no-implicit-builtin-decls.cpp (+1-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 96477ef6ddc9a..b38dafb06e3ca 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -470,6 +470,7 @@ Improvements to Clang's diagnostics
   diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
   a bunch of HLSL types being printed as their C++ equivalents.
 - Clang now consistently quotes expressions in diagnostics.
+- Clang now suggest standard library include path and its associated C++ or C language version.
 - When printing types for diagnostics, clang now doesn't suppress the scopes of
   template arguments contained within nested names.
 - The ``-Wshift-bool`` warning has been added to warn about shifting a boolean. (#GH28334)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f2f2152b8bbbe..96f444544291d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5978,6 +5978,10 @@ def err_template_expansion_into_fixed_list : Error<
   "template|concept}0">;
 def note_parameter_type : Note<
   "parameter of type %0 is declared here">;
+def note_standard_lib_include_suggestion : Note<
+  "maybe try to include %0; '%1' is defined in %0">;
+def note_standard_lib_version : Note<
+  "'%0' is a %1 feature">;
 
 // C++11 Variadic Templates
 def err_template_param_pack_default_arg : Error<
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 9397546c8fc5d..f4c22cc255876 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3611,6 +3611,16 @@ class Sema final : public SemaBase {
                                ParsedType &SuggestedType,
                                bool IsTemplateName = false);
 
+  // Try to suggest the missing standard library include files
+  //
+  // \param SymbolName the symbol name like 'cout'
+  // \param SourceLocation the location of the note being emitted
+  // \param Namespace the namespace that must end with ::, so like 'std::'
+  void NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                            StringRef Namespace);
+  void NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                            const CXXScopeSpec *SS);
+
   /// Attempt to behave like MSVC in situations where lookup of an unqualified
   /// type name has failed in a dependent context. In these situations, we
   /// automatically form a DependentTypeName that will retry lookup in a related
diff --git a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
index 147f505ade058..42bbb5b3f0d8c 100644
--- a/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
+++ b/clang/include/clang/Tooling/Inclusions/StandardLibrary.h
@@ -29,6 +29,27 @@ class NamespaceDecl;
 class DeclContext;
 namespace tooling {
 namespace stdlib {
+enum Version {
+  Unknown,
+
+  // c++ versions
+  CPlusPlusStart,
+  CPlusPlus11,
+  CPlusPlus14,
+  CPlusPlus17,
+  CPlusPlus20,
+  CPlusPlus23,
+  CPlusPlus26,
+  CPlusPlusEnd,
+
+  // c version
+  CStart,
+  C99,
+  C11,
+  CEnd
+};
+
+llvm::StringRef GetAsString(Version Ver);
 
 class Symbol;
 enum class Lang { C = 0, CXX, LastValue = CXX };
@@ -85,6 +106,7 @@ class Symbol {
   std::optional<Header> header() const;
   // Some symbols may be provided by multiple headers.
   llvm::SmallVector<Header> headers() const;
+  Version version() const;
 
 private:
   Symbol(unsigned ID, Lang Language) : ID(ID), Language(Language) {}
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 1ea0cf52933f6..9de0e9ca74c6f 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -226,6 +226,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     HasScopeSpecifier = true;
   }
 
+  // If `FailedNestedNameBuilding` is true, attempt to suggest the standard
+  // include file corresponding to the current `FullNamespace` and symbol.
+  std::string FullNamespace = "";
+  bool FailedNesatedNameBuilding = false;
+
   // Preferred type might change when parsing qualifiers, we need the original.
   auto SavedType = PreferredType;
   while (true) {
@@ -454,6 +459,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
       // We have an identifier followed by a '::'. Lookup this name
       // as the name in a nested-name-specifier.
       Token Identifier = Tok;
+      FullNamespace += Identifier.getIdentifierInfo()->getName();
+      FullNamespace += "::";
+
       SourceLocation IdLoc = ConsumeToken();
       assert(Tok.isOneOf(tok::coloncolon, tok::colon) &&
              "NextToken() not working properly!");
@@ -465,6 +473,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
       if (Actions.ActOnCXXNestedNameSpecifier(
               getCurScope(), IdInfo, EnteringContext, SS, CorrectionFlagPtr,
               OnlyNamespace)) {
+        FailedNesatedNameBuilding = true;
         // Identifier is not recognized as a nested name, but we can have
         // mistyped '::' instead of ':'.
         if (CorrectionFlagPtr && IsCorrectedToColon) {
@@ -554,6 +563,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
     break;
   }
 
+  if (FailedNesatedNameBuilding && Tok.getKind() == tok::identifier) {
+    Actions.NoteStandardIncludes(Tok.getIdentifierInfo()->getName(),
+                                 Tok.getLocation(), FullNamespace);
+  }
+
   // Even if we didn't see any pieces of a nested-name-specifier, we
   // still check whether there is a tilde in this position, which
   // indicates a potential pseudo-destructor.
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 51e0ee10b080b..ff4f583bdd9bf 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -115,4 +115,5 @@ add_clang_library(clangSema
   clangEdit
   clangLex
   clangSupport
+  clangToolingInclusionsStdlib
   )
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e1cccf068b5aa..7d659a6d06f93 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -58,10 +58,12 @@
 #include "clang/Sema/SemaSwift.h"
 #include "clang/Sema/SemaWasm.h"
 #include "clang/Sema/Template.h"
+#include "clang/Tooling/Inclusions/StandardLibrary.h"
 #include "llvm/ADT/STLForwardCompat.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 #include "llvm/Support/SaveAndRestore.h"
 #include "llvm/TargetParser/Triple.h"
@@ -805,6 +807,52 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
     assert(SS && SS->isInvalid() &&
            "Invalid scope specifier has already been diagnosed");
   }
+
+  // don't note standard include files for OpenCL and Objective C
+  if ((getLangOpts().CPlusPlus || getLangOpts().C99) && !getLangOpts().OpenCL &&
+      !getLangOpts().ObjC)
+    NoteStandardIncludes(II->getName(), IILoc, SS);
+}
+
+void Sema::NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                                StringRef Namespace) {
+  using clang::tooling::stdlib::Lang;
+
+  llvm::StringRef HeaderName = "";
+  tooling::stdlib::Lang LangOption = tooling::stdlib::Lang::C;
+  if (getLangOpts().CPlusPlus)
+    LangOption = clang::tooling::stdlib::Lang::CXX;
+
+  if (auto StdSym =
+          tooling::stdlib::Symbol::named(Namespace, SymbolName, LangOption)) {
+    if (auto Header = StdSym->header()) {
+      HeaderName = Header->name();
+      Diag(IILoc, diag::note_standard_lib_include_suggestion)
+          << HeaderName << (Namespace + SymbolName).str();
+
+      // Noting the C/C++ version as well
+      if (StdSym->version() != tooling::stdlib::Unknown) {
+        llvm::StringRef CPlusPlusVersion =
+            tooling::stdlib::GetAsString(StdSym->version());
+
+        Diag(IILoc, diag::note_standard_lib_version)
+            << (Namespace + SymbolName).str() << CPlusPlusVersion;
+      }
+    }
+  }
+}
+
+void Sema::NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
+                                const CXXScopeSpec *SS) {
+  std::string Namespace = "";
+  if (SS) {
+    llvm::raw_string_ostream Stream(Namespace);
+    if (SS->isValid())
+      SS->getScopeRep()->dump(Stream);
+    Stream.flush();
+  }
+
+  NoteStandardIncludes(SymbolName, IILoc, Namespace);
 }
 
 /// Determine whether the given result set contains either a type name
@@ -16784,6 +16832,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
   }
 
   Diag(Loc, diag_id) << &II;
+  NoteStandardIncludes(II.getName(), Loc, "");
   if (Corrected) {
     // If the correction is going to suggest an implicitly defined function,
     // skip the correction as not being a particularly good idea.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index fc2819458a4ff..9015b70deb5d1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2660,11 +2660,17 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
   if (!SS.isEmpty()) {
     Diag(R.getNameLoc(), diag::err_no_member)
         << Name << computeDeclContext(SS, false) << NameRange;
+    NoteStandardIncludes(Name.getAsString(), R.getNameLoc(), &SS);
     return true;
   }
 
   // Give up, we can't recover.
   Diag(R.getNameLoc(), diagnostic) << Name << NameRange;
+
+  // don't note standard include files for OpenCL and Objective C
+  if ((getLangOpts().CPlusPlus || getLangOpts().C99) && !getLangOpts().OpenCL &&
+      !getLangOpts().ObjC)
+    NoteStandardIncludes(Name.getAsString(), R.getNameLoc(), /*Namespace=*/"");
   return true;
 }
 
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672..b3a1921f3c74b 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -6,246 +6,44 @@
 // This file was generated automatically by
 // clang/tools/include-mapping/gen_std.py, DO NOT EDIT!
 //
-// Generated from cppreference offline HTML book (modified on 2018-10-28).
+// Generated from cppreference offline HTML book (modified on 2025-02-10).
 //===----------------------------------------------------------------------===//
 
-SYMBOL(ATOMIC_BOOL_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR16_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR32_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_CHAR_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_FLAG_INIT, None, <stdatomic.h>)
-SYMBOL(ATOMIC_INT_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_LLONG_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_LONG_LOGK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_POINTER_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_SHORT_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(ATOMIC_VAR_INIT, None, <stdatomic.h>)
-SYMBOL(ATOMIC_WCHAR_T_LOCK_FREE, None, <stdatomic.h>)
-SYMBOL(BUFSIZ, None, <stdio.h>)
-SYMBOL(CHAR_BIT, None, <limits.h>)
-SYMBOL(CHAR_MAX, None, <limits.h>)
-SYMBOL(CHAR_MIN, None, <limits.h>)
-SYMBOL(CLOCKS_PER_SEC, None, <time.h>)
-SYMBOL(CMPLX, None, <complex.h>)
-SYMBOL(CMPLXF, None, <complex.h>)
-SYMBOL(CMPLXL, None, <complex.h>)
-SYMBOL(DBL_DECIMAL_DIG, None, <float.h>)
-SYMBOL(DBL_DIG, None, <float.h>)
-SYMBOL(DBL_EPSILON, None, <float.h>)
-SYMBOL(DBL_HAS_SUBNORM, None, <float.h>)
-SYMBOL(DBL_MANT_DIG, None, <float.h>)
-SYMBOL(DBL_MAX, None, <float.h>)
-SYMBOL(DBL_MAX_10_EXP, None, <float.h>)
-SYMBOL(DBL_MAX_EXP, None, <float.h>)
-SYMBOL(DBL_MIN, None, <float.h>)
-SYMBOL(DBL_MIN_10_EXP, None, <float.h>)
-SYMBOL(DBL_MIN_EXP, None, <float.h>)
-SYMBOL(DBL_TRUE_MIN, None, <float.h>)
-SYMBOL(DECIMAL_DIG, None, <float.h>)
-SYMBOL(EDOM, None, <errno.h>)
-SYMBOL(EILSEQ, None, <errno.h>)
-SYMBOL(EOF, None, <stdio.h>)
-SYMBOL(ERANGE, None, <errno.h>)
-SYMBOL(EXIT_FAILURE, None, <stdlib.h>)
-SYMBOL(EXIT_SUCCESS, None, <stdlib.h>)
-SYMBOL(FE_ALL_EXCEPT, None, <fenv.h>)
-SYMBOL(FE_DFL_ENV, None, <fenv.h>)
-SYMBOL(FE_DIVBYZERO, None, <fenv.h>)
-SYMBOL(FE_DOWNWARD, None, <fenv.h>)
-SYMBOL(FE_INEXACT, None, <fenv.h>)
-SYMBOL(FE_INVALID, None, <fenv.h>)
-SYMBOL(FE_OVERFLOW, None, <fenv.h>)
-SYMBOL(FE_TONEAREST, None, <fenv.h>)
-SYMBOL(FE_TOWARDZERO, None, <fenv.h>)
-SYMBOL(FE_UNDERFLOW, None, <fenv.h>)
-SYMBOL(FE_UPWARD, None, <fenv.h>)
 SYMBOL(FILE, None, <stdio.h>)
-SYMBOL(FILENAME_MAX, None, <stdio.h>)
-SYMBOL(FLT_DECIMAL_DIG, None, <float.h>)
-SYMBOL(FLT_DIG, None, <float.h>)
-SYMBOL(FLT_EPSILON, None, <float.h>)
-SYMBOL(FLT_EVAL_METHOD, None, <float.h>)
-SYMBOL(FLT_HAS_SUBNORM, None, <float.h>)
-SYMBOL(FLT_MANT_DIG, None, <float.h>)
-SYMBOL(FLT_MAX, None, <float.h>)
-SYMBOL(FLT_MAX_10_EXP, None, <float.h>)
-SYMBOL(FLT_MAX_EXP, None, <float.h>)
-SYMBOL(FLT_MIN, None, <float.h>)
-SYMBOL(FLT_MIN_10_EXP, None, <float.h>)
-SYMBOL(FLT_MIN_EXP, None, <float.h>)
-SYMBOL(FLT_RADIX, None, <float.h>)
-SYMBOL(FLT_ROUNDS, None, <float.h>)
-SYMBOL(FLT_TRUE_MIN, None, <float.h>)
-SYMBOL(FOPEN_MAX, None, <stdio.h>)
-SYMBOL(FP_INFINITE, None, <math.h>)
-SYMBOL(FP_NAN, None, <math.h>)
-SYMBOL(FP_NORNAL, None, <math.h>)
-SYMBOL(FP_SUBNORMAL, None, <math.h>)
-SYMBOL(FP_ZERO, None, <math.h>)
-SYMBOL(HUGE_VAL, None, <math.h>)
-SYMBOL(HUGE_VALF, None, <math.h>)
-SYMBOL(HUGE_VALL, None, <math.h>)
-SYMBOL(I, None, <complex.h>)
-SYMBOL(INFINITY, None, <math.h>)
-SYMBOL(INT16_MAX, None, <stdint.h>)
-SYMBOL(INT16_MIN, None, <stdint.h>)
-SYMBOL(INT32_MAX, None, <stdint.h>)
-SYMBOL(INT32_MIN, None, <stdint.h>)
-SYMBOL(INT64_MAX, None, <stdint.h>)
-SYMBOL(INT64_MIN, None, <stdint.h>)
-SYMBOL(INT8_MAX, None, <stdint.h>)
-SYMBOL(INT8_MIN, None, <stdint.h>)
-SYMBOL(INTMAX_MAX, None, <stdint.h>)
-SYMBOL(INTMAX_MIN, None, <stdint.h>)
-SYMBOL(INTPTR_MAX, None, <stdint.h>)
-SYMBOL(INTPTR_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST16_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST16_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST32_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST32_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST64_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST64_MIN, None, <stdint.h>)
-SYMBOL(INT_FAST8_MAX, None, <stdint.h>)
-SYMBOL(INT_FAST8_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST16_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST16_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST32_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST32_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST64_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST64_MIN, None, <stdint.h>)
-SYMBOL(INT_LEAST8_MAX, None, <stdint.h>)
-SYMBOL(INT_LEAST8_MIN, None, <stdint.h>)
-SYMBOL(INT_MAX, None, <limits.h>)
-SYMBOL(INT_MIN, None, <limits.h>)
-SYMBOL(LC_ALL, None, <locale.h>)
-SYMBOL(LC_COLLATE, None, <locale.h>)
-SYMBOL(LC_CTYPE, None, <locale.h>)
-SYMBOL(LC_MONETARY, None, <locale.h>)
-SYMBOL(LC_NUMERIC, None, <locale.h>)
-SYMBOL(LC_TIME, None, <locale.h>)
-SYMBOL(LDBL_DECIMAL_DIG, None, <float.h>)
-SYMBOL(LDBL_DIG, None, <float.h>)
-SYMBOL(LDBL_EPSILON, None, <float.h>)
-SYMBOL(LDBL_HAS_SUBNORM, None, <float.h>)
-SYMBOL(LDBL_MANT_DIG, None, <float.h>)
-SYMBOL(LDBL_MAX, None, <float.h>)
-SYMBOL(LDBL_MAX_10_EXP, None, <float.h>)
-SYMBOL(LDBL_MAX_EXP, None, <float.h>)
-SYMBOL(LDBL_MIN, None, <float.h>)
-SYMBOL(LDBL_MIN_10_EXP, None, <float.h>)
-SYMBOL(LDBL_MIN_EXP, None, <float.h>)
-SYMBOL(LDBL_TRUE_MIN, None, <float.h>)
-SYMBOL(LLONG_MAX, None, <limits.h>)
-SYMBOL(LLONG_MIN, None, <limits.h>)
-SYMBOL(LONG_MAX, None, <limits.h>)
-SYMBOL(LONG_MIN, None, <limits.h>)
-SYMBOL(L_tmpnam, None, <stdio.h>)
-SYMBOL(L_tmpnam_s, None, <stdio.h>)
-SYMBOL(MATH_ERREXCEPT, None, <math.h>)
-SYMBOL(MATH_ERRNO, None, <math.h>)
-SYMBOL(MB_CUR_MAX, None, <stdlib.h>)
-SYMBOL(MB_LEN_MAX, None, <limits.h>)
-SYMBOL(NAN, None, <math.h>)
-SYMBOL(ONCE_FLAG_INIT, None, <threads.h>)
-SYMBOL(PTRDIFF_MAX, None, <stdint.h>)
-SYMBOL(PTRDIFF_MIN, None, <stdint.h>)
-SYMBOL(RAND_MAX, None, <stdlib.h>)
-SYMBOL(RSIZE_MAX, None, <stdint.h>)
-SYMBOL(SCHAR_MAX, None, <limits.h>)
-SYMBOL(SCHAR_MIN, None, <limits.h>)
-SYMBOL(SEEK_CUR, None, <stdio.h>)
-SYMBOL(SEEK_END, None, <stdio.h>)
-SYMBOL(SEEK_SET, None, <stdio.h>)
-SYMBOL(SHRT_MAX, None, <limits.h>)
-SYMBOL(SHRT_MIN, None, <limits.h>)
-SYMBOL(SIGABRT, None, <signal.h>)
-SYMBOL(SIGFPE, None, <signal.h>)
-SYMBOL(SIGILL, None, <signal.h>)
-SYMBOL(SIGINT, None, <signal.h>)
-SYMBOL(SIGSEGV, None, <signal.h>)
-SYMBOL(SIGTERM, None, <signal.h>)
-SYMBOL(SIG_ATOMIC_MAX, None, <stdint.h>)
-SYMBOL(SIG_ATOMIC_MIN, None, <stdint.h>)
-SYMBOL(SIG_DFL, None, <signal.h>)
-SYMBOL(SIG_ERR, None, <signal.h>)
-SYMBOL(SIG_IGN, None, <signal.h>)
-SYMBOL(SIZE_MAX, None, <stdint.h>)
-SYMBOL(TIME_UTC, None, <time.h>)
-SYMBOL(TMP_MAX, None, <stdio.h>)
-SYMBOL(TMP_MAX_S, None, <stdio.h>)
-SYMBOL(TSS_DTOR_ITERATIONS, None, <threads.h>)
-SYMBOL(UCHAR_MAX, None, <limits.h>)
-SYMBOL(UINT16_MAX, None, <stdint.h>)
-SYMBOL(UINT32_MAX, None, <stdint.h>)
-SYMBOL(UINT64_MAX, None, <stdint.h>)
-SYMBOL(UINT8_MAX, None, <stdint.h>)
-SYMBOL(UINTMAX_MAX, None, <stdint.h>)
-SYMBOL(UINTPTR_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST16_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST32_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST64_MAX, None, <stdint.h>)
-SYMBOL(UINT_FAST8_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST16_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST32_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST64_MAX, None, <stdint.h>)
-SYMBOL(UINT_LEAST8_MAX, None, <stdint.h>)
-SYMBOL(UINT_MAX, None, <limits.h>)
-SYMBOL(ULLONG_MAX, None, <limits.h>)
-SYMBOL(ULONG_MAX, None, <limits.h>)
-SYMBOL(USHRT_MAX, None, <limits.h>)
-SYMBOL(WCHAR_MAX, None, <wchar.h>)
-SYMBOL(WCHAR_MIN, None, <wchar.h>)
-SYMBOL(WEOF, None, <wchar.h>)
-SYMBOL(WINT_MAX, None, <stdint.h>)
-SYMBOL(WINT_MIN, None, <stdint.h>)
-SYMBOL(_Complex_I, None, <complex.h>)
-SYMBOL(_IOFBF, None, <stdio.h>)
-SYMBOL(_IOLBF, None, <stdio.h>)
-SYMBOL(_IONBF, None, <stdio.h>)
-SYMBOL(_Imaginary_I, None, <complex.h>)
-SYMBOL(__alignas_is_defined, None, <stdalign.h>)
-SYMBOL(__alignof_is_defined, None, <stdalign.h>)
-SYMBOL(abort_handler_s, None, <stdlib.h>)
+SYMBOL_VERSION(_Exit, None, <stdlib.h>, c99)
+SYMBOL(abort, None, <stdlib.h>)
+SYMBOL_VERSION(abort_handler_s, None, <stdlib.h>, c11)
 SYMBOL(abs, None, <stdlib.h>)
 SYMBOL(acos, None, <math.h>)
-SYMBOL(acosf, None, <math.h>)
-SYMBOL(acosh, None, <math.h>)
-SYMBOL(acoshf, None, <math.h>)
-SYMBOL(acoshl, None, <math.h>)
-SYMBOL(acosl, None, <math.h>)
-SYMBOL(alignas, None, <stdalign.h>)
-SYMBOL(aligned_alloc, None, <stdlib.h>)
-SYMBOL(alignof, None, <stdalign.h>)
-SYMBOL(and, None, <iso646.h>)
-SYMBOL(and_eq, None, <iso646.h>)
+SYMBOL_VERSION(acosf, None, <math.h>, c99)
+SYMBOL_VERSION(acosh, None, <math.h>, c99)
+SYMBOL_VERSION(acoshf, None, <math.h>, c99)
+SYMBOL_VERSION(acoshl, None, <math.h>, c99)
+SYMBOL_VERSION(acosl, None, <math.h>, c99)
+SYMBOL_VERSION(aligned_alloc, None, <stdlib.h>, c11)
 SYMBOL(asctime, None, <time.h>)
-SYMBOL(asctime_s, None, <time.h>)
+SYMBOL_VERSION(asctime_s, None, <time.h>, c11)
 SYMBOL(asin, None, <math.h>)
-SYMBOL(asinf, None, <math.h>)
-SYMBOL(asinh, None, <math.h>)
-SYMBOL(asinhf, None, <math.h>)
-SYMBOL(asinhl, None, <math.h>)
-SYMBOL(asinl, None, <math.h>)
-SYMBOL(assert, None, <assert.h>)
-SYMBOL(at_quick_exit, None, <stdlib.h>)
+SYMBOL_VERSION(asinf, None, <math.h>, c99)
+SYMBOL_VERSION(asinh, None, <math.h>, c99)
+SYMBOL_VERSION(asinhf, None, <math.h>, c99)
+SYMBOL_VERSION(asinhl, None, <math.h>, c99)
+SYMBOL_VERSION(asinl, None, <math.h>, c99)
+SYMBOL_VERSION(at_quick_exit, None, <stdlib.h>, c11)
 SYMBOL(atan, None, <math.h>)
 SYMBOL(atan2, None, <math.h>)
-SYMBOL(atan2f, None, <math.h>)
-SYMBOL(atan2l, None, <math.h>)
-SYMBOL(atanf, None, <math.h>)
-SYMBOL(atanh, None, <math.h>)
-SYMBOL(atanhf, None, <math.h>)
-SYMBOL(atanhl, None, <math.h>)
-SYMBOL(atanl, None, <math.h>)
+SYMBOL_VERSION(atan2f, None, <math.h>, c99)
+SYMBOL_VERSION(atan2l, None, <math.h>, c99)
+SYMBOL_VERSION(atanf, None, <math.h>, c99)
+SYMBOL_VERSION(atanh, None, <math.h>, c99)
+SYMBOL_VERSION(atanhf, None, <math.h>, c99)
+SYMBOL_VERSION(atanhl, None, <math.h>, c99)
+SYMBOL_VERSION(atanl, None, <math.h>, c99)
 SYMBOL(atexit, None, <stdlib.h>)
 SYMBOL(atof, None, <stdlib.h>)
 SYMBOL(atoi, None, <stdlib.h>)
 SYMBOL(atol, None, <stdlib.h>)
-SYMBOL(atoll, None, <stdlib.h>)
-SYMBOL(atomic_bool, None, <stdatomic.h>)
-SYMBOL(atomic_char, None, <stdatomic.h>)
-SYMBOL(atomic_char16_t, None, <stdatomic.h>)
-SYMBOL(atomic_char32_t, None, <stdatomic.h>)
+SYMBOL_VERSION(atoll,...
[truncated]

@Mr-Anyone Mr-Anyone marked this pull request as draft June 28, 2025 16:50
@Mr-Anyone Mr-Anyone force-pushed the include_suggestions_pr branch from 734e586 to f671c52 Compare June 29, 2025 02:22
Copy link

github-actions bot commented Jun 29, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@Mr-Anyone Mr-Anyone force-pushed the include_suggestions_pr branch from f671c52 to 1a01836 Compare June 29, 2025 02:28
@Mr-Anyone Mr-Anyone marked this pull request as ready for review June 29, 2025 03:32
Clang now tries to suggest and hint standard library include file by emitting
the following.

```
    4 |     std::unordered_map<std::string, std::string> map;
      |          ^~~~~~~~~~~~~
main.cpp:4:10: note: maybe try to include <unordered_map>; 'std::unordered_map' is defined in <unordered_map>
main.cpp:4:10: note: 'std::unordered_map' is a c++11 feature
main.cpp:4:42: note: maybe try to include <string>; 'std::string' is defined in <string>
```

This works for both C and C++.

fixes llvm#120388
@Mr-Anyone Mr-Anyone force-pushed the include_suggestions_pr branch from 1a01836 to a2b2210 Compare June 30, 2025 05:19
@shafik shafik requested review from zyn0217 and erichkeane June 30, 2025 22:17
Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really a fan of how we're doing this. This should only be caused by a failed lookup. This also seems about 2x as complicated as it needs to be. I like the idea ehre, but not at this level of complexity.

@AaronBallman perhaps has a better idea of extended tooling.

@@ -478,6 +478,7 @@ Improvements to Clang's diagnostics
diagnostics. This fixes a bunch of `bool` being printed as `_Bool`, and also
a bunch of HLSL types being printed as their C++ equivalents.
- Clang now consistently quotes expressions in diagnostics.
- Clang now suggest standard library include path and its associated C++ or C language version.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Clang now suggest standard library include path and its associated C++ or C language version.
- Clang now suggests including standard library headers when encountering standard types.

@@ -5990,6 +5990,10 @@ def err_template_expansion_into_fixed_list : Error<
"template|concept}0">;
def note_parameter_type : Note<
"parameter of type %0 is declared here">;
def note_standard_lib_include_suggestion : Note<
"maybe try to include %0; '%1' is defined in %0">;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"maybe try to include %0; '%1' is defined in %0">;
"'%1' is defined in %0; did you mean to include it?">;

@@ -29,6 +29,27 @@ class NamespaceDecl;
class DeclContext;
namespace tooling {
namespace stdlib {
enum Version {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have enums for standards versions elsewhere, I don't want us maintaining ANOTHER one. So I'm against this enum entirely.

def note_standard_lib_include_suggestion : Note<
"maybe try to include %0; '%1' is defined in %0">;
def note_standard_lib_version : Note<
"'%0' is a %1 feature">;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably be doing something more like:
"'%0::%1' is a %enum_select..." for this.

// \param SymbolName the symbol name like 'cout'
// \param SourceLocation the location of the note being emitted
// \param Namespace the namespace that must end with ::, so like 'std::'
void NoteStandardIncludes(StringRef SymbolName, SourceLocation IILoc,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really a fan of this interface. Unless it is particularly easy, we shouldn't be forcing the inclusion of the '::' in this interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, the interface in clangToolingInclusionsStdlib requires the inclusion of ::, so Namesace+SymbolName gives you the full name. I am fine with removing the inclusion of :: at the end.

// If `FailedNestedNameBuilding` is true, attempt to suggest the standard
// include file corresponding to the current `FullNamespace` and symbol.
std::string FullNamespace = "";
bool FailedNesatedNameBuilding = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool FailedNesatedNameBuilding = false;
bool FailedNestedNameBuilding = false;

@@ -454,6 +459,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
// We have an identifier followed by a '::'. Lookup this name
// as the name in a nested-name-specifier.
Token Identifier = Tok;
FullNamespace += Identifier.getIdentifierInfo()->getName();
FullNamespace += "::";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is extra work, just make it a part of the printing, not here. Better yet, instead of storing FullNameSpace, just store the IdentifierInfo list.

@@ -465,6 +473,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
if (Actions.ActOnCXXNestedNameSpecifier(
getCurScope(), IdInfo, EnteringContext, SS, CorrectionFlagPtr,
OnlyNamespace)) {
FailedNesatedNameBuilding = true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we ONLY are going to want to suggest things of the pattern NS::TypeName. So ensuring we have hte 'full name' isn't really necessary. I think we can just store the namespace and identifier.

@@ -554,6 +563,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier(
break;
}

if (FailedNesatedNameBuilding && Tok.getKind() == tok::identifier) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parser isn't really the right place to do this. This is very much a 'sema' diagnostic/suggestion. This should happen not here, but on failed lookup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I completed agree with you for the fact that this is really ugly code here.

The problem I am trying to solve here is when there is no declaration for the std namespace.

// this is the entire file 
void some_func(){
     std::cout << "some func has been called" << std::endl; 
}

Here building the nested name will fail because there is no namespace std being defined anywhere, so a name lookup for cout is never performed (as far as I can tell, there could be something I am missing here). I am not sure if there is an easy fix to that in Sema level.

However, something like the following would work cause the suggestion to trigger. It is okay if I revert this file?

namespace std {};

// this is the entire file 
void some_func(){
     std::cout << "some func has been called" << std::endl; 
}

<< HeaderName << (Namespace + SymbolName).str();

// Noting the C/C++ version as well
if (StdSym->version() != tooling::stdlib::Unknown) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version stuff we should be handling via our diagnostic, not doing it this way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Suggest include file for popular standard functions
3 participants