llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Oleksandr T. (a-tarasyuk) <details> <summary>Changes</summary> This patch enhances Clang's diagnosis for unknown attributes by providing typo correction suggestions for known attributes. ```cpp [[gmu::deprected]] // expected-warning {{unknown attribute 'gmu::deprected' ignored; did you mean 'gnu::deprecated'?}} int f1(void) { return 0; } [[deprected]] // expected-warning {{unknown attribute 'deprected' ignored; did you mean 'deprecated'?}} int f2(void) { return 0; } ``` --- Patch is 30.20 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140629.diff 20 Files Affected: - (modified) clang/docs/ReleaseNotes.rst (+2) - (modified) clang/include/clang/Basic/AttributeCommonInfo.h (+5) - (modified) clang/include/clang/Basic/Attributes.h (+4) - (modified) clang/include/clang/Basic/CMakeLists.txt (+6) - (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+2) - (added) clang/include/clang/Basic/SimpleTypoCorrection.h (+35) - (modified) clang/include/clang/Sema/Sema.h (+2) - (modified) clang/lib/AST/CommentSema.cpp (+26-71) - (modified) clang/lib/Basic/Attributes.cpp (+104-49) - (modified) clang/lib/Basic/CMakeLists.txt (+1) - (added) clang/lib/Basic/SimpleTypoCorrection.cpp (+52) - (modified) clang/lib/Sema/SemaDeclAttr.cpp (+15-3) - (modified) clang/lib/Sema/SemaType.cpp (+1-3) - (modified) clang/test/Parser/cxx0x-attributes.cpp (+1-1) - (modified) clang/test/Sema/attr-c2x.c (+2-2) - (modified) clang/test/Sema/unknown-attributes.c (+13-3) - (modified) clang/test/SemaCXX/cxx11-gnu-attrs.cpp (+1-1) - (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+27) - (modified) clang/utils/TableGen/TableGen.cpp (+6) - (modified) clang/utils/TableGen/TableGenBackends.h (+2) ``````````diff diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ac9baf229b489..deee00128c1fa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -561,6 +561,8 @@ Improvements to Clang's diagnostics - Fixed a crash when checking a ``__thread``-specified variable declaration with a dependent type in C++. (#GH140509) +- Clang now suggests corrections for unknown attribute names. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index 6db7b53317e7d..b4b8345b4ed40 100644 --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -21,6 +21,8 @@ namespace clang { class ASTRecordWriter; class IdentifierInfo; +class LangOptions; +class TargetInfo; class AttributeCommonInfo { public: @@ -196,6 +198,9 @@ class AttributeCommonInfo { /// with surrounding underscores removed as appropriate (e.g. /// __gnu__::__attr__ will be normalized to gnu::attr). std::string getNormalizedFullName() const; + std::optional<std::string> + getCorrectedFullName(const TargetInfo &Target, + const LangOptions &LangOpts) const; SourceRange getNormalizedRange() const; bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } diff --git a/clang/include/clang/Basic/Attributes.h b/clang/include/clang/Basic/Attributes.h index 99bb668fe32d0..9cf6fb3d89019 100644 --- a/clang/include/clang/Basic/Attributes.h +++ b/clang/include/clang/Basic/Attributes.h @@ -19,6 +19,10 @@ class TargetInfo; /// Return the version number associated with the attribute if we /// recognize and implement the attribute specified by the given information. +int hasAttribute(AttributeCommonInfo::Syntax Syntax, llvm::StringRef ScopeName, + llvm::StringRef AttrName, const TargetInfo &Target, + const LangOptions &LangOpts, bool CheckPlugins); + int hasAttribute(AttributeCommonInfo::Syntax Syntax, const IdentifierInfo *Scope, const IdentifierInfo *Attr, const TargetInfo &Target, const LangOptions &LangOpts); diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 265ea1fc06494..1873878e2e46b 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -79,6 +79,12 @@ clang_tablegen(CXX11AttributeInfo.inc -gen-cxx11-attribute-info TARGET CXX11AttributeInfo ) + clang_tablegen(AttributeSpellingList.inc -gen-attribute-spelling-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET AttributeSpellingList + ) + clang_tablegen(Builtins.inc -gen-clang-builtins SOURCE Builtins.td TARGET ClangBuiltins) diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index e4d94fefbbf3d..0bd8a423c393e 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -181,6 +181,8 @@ def err_opencl_unknown_type_specifier : Error< def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup<UnknownAttributes>; +def warn_unknown_attribute_ignored_suggestion : Warning< + "unknown attribute %0 ignored; did you mean '%1'?">, InGroup<UnknownAttributes>; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup<IgnoredAttributes>; def err_keyword_not_supported_on_target : Error< diff --git a/clang/include/clang/Basic/SimpleTypoCorrection.h b/clang/include/clang/Basic/SimpleTypoCorrection.h new file mode 100644 index 0000000000000..4cd104f79aebe --- /dev/null +++ b/clang/include/clang/Basic/SimpleTypoCorrection.h @@ -0,0 +1,35 @@ +#ifndef LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H +#define LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + +class IdentifierInfo; + +class SimpleTypoCorrection { + StringRef BestCandidate; + StringRef Typo; + + const unsigned MaxEditDistance; + unsigned BestEditDistance; + unsigned BestIndex; + unsigned NextIndex; + +public: + explicit SimpleTypoCorrection(StringRef Typo) + : BestCandidate(), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), + BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {} + + void add(const StringRef Candidate); + void add(const char *Candidate); + void add(const IdentifierInfo *Candidate); + + std::optional<StringRef> getCorrection() const; + bool hasCorrection() const; + unsigned getCorrectionIndex() const; +}; +} // namespace clang + +#endif // LLVM_CLANG_BASIC_SIMPLETYPOCORRECTION_H diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ec67087aeea4..d7a3a81065d33 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5033,6 +5033,8 @@ class Sema final : public SemaBase { /// which might be lying around on it. void checkUnusedDeclAttributes(Declarator &D); + void DiagnoseUnknownAttribute(const ParsedAttr &AL); + /// DeclClonePragmaWeak - clone existing decl (maybe definition), /// \#pragma weak needs a non-definition decl and source may not have one. NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, const IdentifierInfo *II, diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index bd2206bb8a3bc..fb745fc560d2f 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -13,6 +13,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/Basic/DiagnosticComment.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/SimpleTypoCorrection.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSwitch.h" @@ -975,69 +976,22 @@ unsigned Sema::resolveParmVarReference(StringRef Name, return ParamCommandComment::InvalidParamIndex; } -namespace { -class SimpleTypoCorrector { - const NamedDecl *BestDecl; - - StringRef Typo; - const unsigned MaxEditDistance; - - unsigned BestEditDistance; - unsigned BestIndex; - unsigned NextIndex; - -public: - explicit SimpleTypoCorrector(StringRef Typo) - : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), - BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {} - - void addDecl(const NamedDecl *ND); - - const NamedDecl *getBestDecl() const { - if (BestEditDistance > MaxEditDistance) - return nullptr; - - return BestDecl; - } +unsigned +Sema::correctTypoInParmVarReference(StringRef Typo, + ArrayRef<const ParmVarDecl *> ParamVars) { + SimpleTypoCorrection STC(Typo); + for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) { + const ParmVarDecl *Param = ParamVars[i]; + if (!Param) + continue; - unsigned getBestDeclIndex() const { - assert(getBestDecl()); - return BestIndex; + STC.add(Param->getIdentifier()); } -}; - -void SimpleTypoCorrector::addDecl(const NamedDecl *ND) { - unsigned CurrIndex = NextIndex++; - - const IdentifierInfo *II = ND->getIdentifier(); - if (!II) - return; - StringRef Name = II->getName(); - unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); - if (MinPossibleEditDistance > 0 && - Typo.size() / MinPossibleEditDistance < 3) - return; + if (STC.hasCorrection()) + return STC.getCorrectionIndex(); - unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); - if (EditDistance < BestEditDistance) { - BestEditDistance = EditDistance; - BestDecl = ND; - BestIndex = CurrIndex; - } -} -} // end anonymous namespace - -unsigned Sema::correctTypoInParmVarReference( - StringRef Typo, - ArrayRef<const ParmVarDecl *> ParamVars) { - SimpleTypoCorrector Corrector(Typo); - for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) - Corrector.addDecl(ParamVars[i]); - if (Corrector.getBestDecl()) - return Corrector.getBestDeclIndex(); - else - return ParamCommandComment::InvalidParamIndex; + return ParamCommandComment::InvalidParamIndex; } namespace { @@ -1079,16 +1033,18 @@ bool Sema::resolveTParamReference( namespace { void CorrectTypoInTParamReferenceHelper( - const TemplateParameterList *TemplateParameters, - SimpleTypoCorrector &Corrector) { + const TemplateParameterList *TemplateParameters, + SimpleTypoCorrection &STC) { for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { const NamedDecl *Param = TemplateParameters->getParam(i); - Corrector.addDecl(Param); + if (!Param) + continue; + + STC.add(Param->getIdentifier()); if (const TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) - CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), - Corrector); + CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), STC); } } } // end anonymous namespace @@ -1096,13 +1052,12 @@ void CorrectTypoInTParamReferenceHelper( StringRef Sema::correctTypoInTParamReference( StringRef Typo, const TemplateParameterList *TemplateParameters) { - SimpleTypoCorrector Corrector(Typo); - CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector); - if (const NamedDecl *ND = Corrector.getBestDecl()) { - const IdentifierInfo *II = ND->getIdentifier(); - assert(II && "SimpleTypoCorrector should not return this decl"); - return II->getName(); - } + SimpleTypoCorrection STC(Typo); + CorrectTypoInTParamReferenceHelper(TemplateParameters, STC); + + if (auto CorrectedTParamReference = STC.getCorrection()) + return *CorrectedTParamReference; + return StringRef(); } diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index 8ff5cc54ccc93..0c0a816c78039 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/ParsedAttrInfo.h" +#include "clang/Basic/SimpleTypoCorrection.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringMap.h" @@ -22,30 +23,37 @@ using namespace clang; -static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, - StringRef ScopeName, const TargetInfo &Target, - const LangOptions &LangOpts) { +static StringRef canonicalizeScopeName(StringRef Name) { + // Normalize the scope name, but only for gnu and clang attributes. + if (Name == "__gnu__") + return "gnu"; -#include "clang/Basic/AttrHasAttributeImpl.inc" + if (Name == "_Clang") + return "clang"; - return 0; + return Name; } -int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, - const IdentifierInfo *Scope, const IdentifierInfo *Attr, - const TargetInfo &Target, const LangOptions &LangOpts, - bool CheckPlugins) { - StringRef Name = Attr->getName(); +static StringRef canonicalizeAttrName(StringRef Name) { // Normalize the attribute name, __foo__ becomes foo. if (Name.size() >= 4 && Name.starts_with("__") && Name.ends_with("__")) - Name = Name.substr(2, Name.size() - 4); + return Name.substr(2, Name.size() - 4); - // Normalize the scope name, but only for gnu and clang attributes. - StringRef ScopeName = Scope ? Scope->getName() : ""; - if (ScopeName == "__gnu__") - ScopeName = "gnu"; - else if (ScopeName == "_Clang") - ScopeName = "clang"; + return Name; +} + +static int hasAttributeImpl(AttributeCommonInfo::Syntax Syntax, StringRef Name, + StringRef ScopeName, const TargetInfo &Target, + const LangOptions &LangOpts) { +#include "clang/Basic/AttrHasAttributeImpl.inc" + return 0; +} + +int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, StringRef ScopeName, + StringRef Name, const TargetInfo &Target, + const LangOptions &LangOpts, bool CheckPlugins) { + ScopeName = canonicalizeScopeName(ScopeName); + Name = canonicalizeAttrName(Name); // As a special case, look for the omp::sequence and omp::directive // attributes. We support those, but not through the typical attribute @@ -72,6 +80,14 @@ int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, return 0; } +int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, + const IdentifierInfo *Scope, const IdentifierInfo *Attr, + const TargetInfo &Target, const LangOptions &LangOpts, + bool CheckPlugins) { + return hasAttribute(Syntax, Scope ? Scope->getName() : "", Attr->getName(), + Target, LangOpts, CheckPlugins); +} + int clang::hasAttribute(AttributeCommonInfo::Syntax Syntax, const IdentifierInfo *Scope, const IdentifierInfo *Attr, const TargetInfo &Target, const LangOptions &LangOpts) { @@ -90,25 +106,25 @@ const char *attr::getSubjectMatchRuleSpelling(attr::SubjectMatchRule Rule) { } static StringRef -normalizeAttrScopeName(const IdentifierInfo *Scope, +normalizeAttrScopeName(StringRef ScopeName, AttributeCommonInfo::Syntax SyntaxUsed) { - if (!Scope) - return ""; - - // Normalize the "__gnu__" scope name to be "gnu" and the "_Clang" scope name - // to be "clang". - StringRef ScopeName = Scope->getName(); if (SyntaxUsed == AttributeCommonInfo::AS_CXX11 || - SyntaxUsed == AttributeCommonInfo::AS_C23) { - if (ScopeName == "__gnu__") - ScopeName = "gnu"; - else if (ScopeName == "_Clang") - ScopeName = "clang"; - } + SyntaxUsed == AttributeCommonInfo::AS_C23) + return canonicalizeScopeName(ScopeName); + return ScopeName; } -static StringRef normalizeAttrName(const IdentifierInfo *Name, +static StringRef +normalizeAttrScopeName(const IdentifierInfo *ScopeName, + AttributeCommonInfo::Syntax SyntaxUsed) { + if (ScopeName) + return normalizeAttrScopeName(ScopeName->getName(), SyntaxUsed); + + return ""; +} + +static StringRef normalizeAttrName(StringRef AttrName, StringRef NormalizedScopeName, AttributeCommonInfo::Syntax SyntaxUsed) { // Normalize the attribute name, __foo__ becomes foo. This is only allowable @@ -119,10 +135,9 @@ static StringRef normalizeAttrName(const IdentifierInfo *Name, SyntaxUsed == AttributeCommonInfo::AS_C23) && (NormalizedScopeName.empty() || NormalizedScopeName == "gnu" || NormalizedScopeName == "clang")); - StringRef AttrName = Name->getName(); - if (ShouldNormalize && AttrName.size() >= 4 && AttrName.starts_with("__") && - AttrName.ends_with("__")) - AttrName = AttrName.slice(2, AttrName.size() - 2); + + if (ShouldNormalize) + return canonicalizeAttrName(AttrName); return AttrName; } @@ -137,16 +152,11 @@ bool AttributeCommonInfo::isClangScope() const { #include "clang/Sema/AttrParsedAttrKinds.inc" -static SmallString<64> normalizeName(const IdentifierInfo *Name, - const IdentifierInfo *Scope, +static SmallString<64> normalizeName(StringRef AttrName, StringRef ScopeName, AttributeCommonInfo::Syntax SyntaxUsed) { - StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); - StringRef AttrName = normalizeAttrName(Name, ScopeName, SyntaxUsed); - - std::string StrAttrName = AttrName.str(); - if (SyntaxUsed == AttributeCommonInfo::AS_HLSLAnnotation) - StrAttrName = AttrName.lower(); - + std::string StrAttrName = SyntaxUsed == AttributeCommonInfo::AS_HLSLAnnotation + ? AttrName.lower() + : AttrName.str(); SmallString<64> FullName = ScopeName; if (!ScopeName.empty()) { assert(SyntaxUsed == AttributeCommonInfo::AS_CXX11 || @@ -154,10 +164,18 @@ static SmallString<64> normalizeName(const IdentifierInfo *Name, FullName += "::"; } FullName += StrAttrName; - return FullName; } +static SmallString<64> normalizeName(const IdentifierInfo *Name, + const IdentifierInfo *Scope, + AttributeCommonInfo::Syntax SyntaxUsed) { + StringRef ScopeName = normalizeAttrScopeName(Scope, SyntaxUsed); + StringRef AttrName = + normalizeAttrName(Name->getName(), ScopeName, SyntaxUsed); + return normalizeName(AttrName, ScopeName, SyntaxUsed); +} + AttributeCommonInfo::Kind AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, const IdentifierInfo *ScopeName, @@ -167,8 +185,8 @@ AttributeCommonInfo::getParsedKind(const IdentifierInfo *Name, AttributeCommonInfo::AttrArgsInfo AttributeCommonInfo::getCXX11AttrArgsInfo(const IdentifierInfo *Name) { - StringRef AttrName = - normalizeAttrName(Name, /*NormalizedScopeName*/ "", Syntax::AS_CXX11); + StringRef AttrName = normalizeAttrName( + Name->getName(), /*NormalizedScopeName*/ "", Syntax::AS_CXX11); #define CXX11_ATTR_ARGS_INFO return llvm::StringSwitch<AttributeCommonInfo::AttrArgsInfo>(AttrName) #include "clang/Basic/CXX11AttributeInfo.inc" @@ -203,10 +221,47 @@ unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { // attribute spell list index matching code. auto Syntax = static_cast<AttributeCommonInfo::Syntax>(getSyntax()); StringRef ScopeName = normalizeAttrScopeName(getScopeName(), Syntax); - StringRef Name = normalizeAttrName(getAttrName(), ScopeName, Syntax); - + StringRef Name = + normalizeAttrName(getAttrName()->getName(), ScopeName, Syntax); AttributeCommonInfo::Scope ComputedScope = getScopeFromNormalizedScopeName(ScopeName); #include "clang/Sema/AttrSpellingListIndex.inc" } + +#include "clang/Basic/AttributeSpellingList.inc" + +std::optional<std::string> +AttributeCommonInfo::getCorrectedFullName(const TargetInfo &Target, + const LangOptions &LangOpts) const { + StringRef ScopeName = normalizeAttrScopeName(getScopeName(), getSyntax()); + if (ScopeName.size() > 0 && + llvm::none_of(AttrScopeSpellingList, + [&](const char *S) { return S == ScopeName; })) { + SimpleTypoCorrection STC(ScopeName); + for (const auto &Scope : AttrScopeSpellingList) + STC.add(Scope); + + if (auto CorrectedScopeName = STC.getCorrection()) + ScopeName = *CorrectedScopeName; + } + + StringRef AttrName = + normalizeAttrName(getAttrName()->getName(), ScopeName, getSyntax()); + if (llvm::none_of(AttrSpellingList, + [&](const char *A) { return A == AttrName; })) { + SimpleTypoCorrection STC(AttrName); + for (const auto &Attr : AttrSpellingList) + STC.add(Attr); + + if (auto CorrectedAttrName = STC.getCorrection()) + AttrName = *CorrectedAttrName; + } + + if (hasAttribute(getSyntax(), ScopeName, AttrName, Target, LangOpts, + /*CheckPlugins=*/true)) + return static_cast<std::string>( + normalizeName(AttrName, ScopeName, getSyntax())); + + return std::nullopt; +} diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt index 0eacf79f5d478..f8a31c890ac4d 100644 --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -86,6 +86,7 @@ add_clang_library(clangBasic SanitizerSpecialCaseList.cpp Sanitizers.cpp Sarif.cpp + SimpleTypoCorrection.cpp SourceLocation.cpp SourceManager.cpp SourceMgrAdapter.cpp diff --git a/clang/lib/Basic/SimpleTypoCorrection.cpp b/clang/lib/Basic/SimpleTypoCorrection.cpp new file mode 100644 index 0000000000000..c98b89d9f080d --- /dev/null +++ b/clang/lib/Basic/SimpleTypoCorrection.cpp @@ -0,0 +1,52 @@ +#include "clang/Basic/SimpleTypoCorrection.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; + +void SimpleTypoCorr... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/140629 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits