-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Vincent (Mr-Anyone) ChangesClang now tries to suggest and hint standard library include file by emitting the following.
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:
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]
|
@llvm/pr-subscribers-clang-modules Author: Vincent (Mr-Anyone) ChangesClang now tries to suggest and hint standard library include file by emitting the following.
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:
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]
|
734e586
to
f671c52
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
f671c52
to
1a01836
Compare
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
1a01836
to
a2b2210
Compare
There was a problem hiding this 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 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">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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 { |
There was a problem hiding this comment.
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">; |
There was a problem hiding this comment.
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, |
There was a problem hiding this 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 this interface. Unless it is particularly easy, we shouldn't be forcing the inclusion of the '::' in this interface.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 += "::"; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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.
Clang now tries to suggest and hint standard library include file by emitting the following.
This works for both C and C++.
fixes #120388