diff options
author | cor3ntin <corentinjabot@gmail.com> | 2025-05-31 12:26:49 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-31 12:26:49 +0200 |
commit | 6f7268e204ed0a2c014324828e0582d90e8fcd04 (patch) | |
tree | 9a9913211ff75b1eb91f129e814dd31d6c43aa50 /clang/lib | |
parent | 3a989344741949be04bc2512a4633edc1c0e69d6 (diff) | |
download | llvm-6f7268e204ed0a2c014324828e0582d90e8fcd04.zip llvm-6f7268e204ed0a2c014324828e0582d90e8fcd04.tar.gz llvm-6f7268e204ed0a2c014324828e0582d90e8fcd04.tar.bz2 |
[Clang] Improve infrastructure for libstdc++ workarounds (#141977)
This introduces a way detect the libstdc++ version, use that to enable
workarounds.
The version is cached.
This should make it easier in the future to find and remove these hacks.
I did not find the need for enabling a hack between or after specific
versions, so it's left as a future exercise.
We can extend this fature to other libraries as the need arise.
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Lex/PPExpressions.cpp | 46 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExceptionSpec.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 24 |
6 files changed, 71 insertions, 35 deletions
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index cf7e32b..118d4ae 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/lib/Lex/PPExpressions.cpp @@ -979,3 +979,49 @@ Preprocessor::EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro, return EvaluateDirectiveExpression(IfNDefMacro, Tok, EvaluatedDefined, CheckForEoD); } + +static std::optional<CXXStandardLibraryVersionInfo> +getCXXStandardLibraryVersion(Preprocessor &PP, StringRef MacroName, + CXXStandardLibraryVersionInfo::Library Lib) { + MacroInfo *Macro = PP.getMacroInfo(PP.getIdentifierInfo(MacroName)); + + if (!Macro || Macro->getNumTokens() != 1 || !Macro->isObjectLike()) + return std::nullopt; + + const Token &RevisionDateTok = Macro->getReplacementToken(0); + + bool Invalid = false; + llvm::SmallVector<char, 10> Buffer; + llvm::StringRef RevisionDate = + PP.getSpelling(RevisionDateTok, Buffer, &Invalid); + if (!Invalid) { + unsigned Value; + // We don't use NumericParser to avoid diagnostics + if (!RevisionDate.consumeInteger(10, Value)) + return CXXStandardLibraryVersionInfo{Lib, Value}; + } + return CXXStandardLibraryVersionInfo{CXXStandardLibraryVersionInfo::Unknown, + 0}; +} + +std::optional<unsigned> Preprocessor::getStdLibCxxVersion() { + if (!CXXStandardLibraryVersion) + CXXStandardLibraryVersion = getCXXStandardLibraryVersion( + *this, "__GLIBCXX__", CXXStandardLibraryVersionInfo::LibStdCXX); + if (!CXXStandardLibraryVersion) + return std::nullopt; + + if (CXXStandardLibraryVersion->Lib == + CXXStandardLibraryVersionInfo::LibStdCXX) + return CXXStandardLibraryVersion->Version; + return std::nullopt; +} + +bool Preprocessor::NeedsStdLibCxxWorkaroundBefore(unsigned FixedVersion) { + assert(FixedVersion >= 2000'00'00 && FixedVersion <= 2100'00'00 && + "invalid value for __GLIBCXX__"); + std::optional<unsigned> Ver = getStdLibCxxVersion(); + if (!Ver) + return false; + return *Ver < FixedVersion; +} diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 4a73599..55e078f 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13198,6 +13198,7 @@ NamedDecl *Sema::BuildUsingDeclaration( if (getLangOpts().CPlusPlus14 && II && II->isStr("gets") && CurContext->isStdNamespace() && isa<TranslationUnitDecl>(LookupContext) && + PP.NeedsStdLibCxxWorkaroundBefore(2016'12'21) && getSourceManager().isInSystemHeader(UsingLoc)) return nullptr; UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation, SS.getScopeRep(), diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index c83eab5..c692f82 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -18,6 +18,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallPtrSet.h" #include <optional> @@ -44,6 +45,8 @@ static const FunctionProtoType *GetUnderlyingFunction(QualType T) bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { auto *RD = dyn_cast<CXXRecordDecl>(CurContext); + if (!getPreprocessor().NeedsStdLibCxxWorkaroundBefore(2016'04'27)) + return false; // All the problem cases are member functions named "swap" within class // templates declared directly within namespace std or std::__debug or // std::__profile. diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 776cb02..5d870f07 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Designator.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" @@ -641,8 +642,10 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, // in that case. stlport does so too. // Look for std::__debug for libstdc++, and for std:: for stlport. // This is effectively a compiler-side implementation of LWG2193. - if (!InitSeq && EmptyInitList && InitSeq.getFailureKind() == - InitializationSequence::FK_ExplicitConstructor) { + if (!InitSeq && EmptyInitList && + InitSeq.getFailureKind() == + InitializationSequence::FK_ExplicitConstructor && + SemaRef.getPreprocessor().NeedsStdLibCxxWorkaroundBefore(2014'04'22)) { OverloadCandidateSet::iterator Best; OverloadingResult O = InitSeq.getFailedCandidateSet() diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 10e7823..1d8fea1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4444,16 +4444,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) { !Var->getDeclContext()->isStdNamespace()) return false; - MacroInfo *MacroGLIBCXX = - PP.getMacroInfo(PP.getIdentifierInfo("__GLIBCXX__")); - - if (!MacroGLIBCXX || MacroGLIBCXX->getNumTokens() != 1) - return false; - - const Token &RevisionDateTok = MacroGLIBCXX->getReplacementToken(0); - bool Invalid = false; - std::string RevisionDate = PP.getSpelling(RevisionDateTok, &Invalid); - + // Checking old versions of libstdc++ is not needed because 15.1 is the first + // release in which users can access std::format_kind. // We can use 20250520 as the final date, see the following commits. // GCC releases/gcc-15 branch: // https://gcc.gnu.org/g:fedf81ef7b98e5c9ac899b8641bb670746c51205 @@ -4461,18 +4453,7 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) { // GCC master branch: // https://gcc.gnu.org/g:9361966d80f625c5accc25cbb439f0278dd8b278 // https://gcc.gnu.org/g:c65725eccbabf3b9b5965f27fff2d3b9f6c75930 - StringRef FixDate = "20250520"; - - if (Invalid) - return false; - - // The format of the revision date is in compressed ISO date format. - // See https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_macros.html - // So we can use string comparison. - // - // Checking old versions of libstdc++ is not needed because 15.1 is the first - // release in which users can access std::format_kind. - return RevisionDate.size() == 8 && RevisionDate < FixDate; + return PP.NeedsStdLibCxxWorkaroundBefore(2025'05'20); } } // end anonymous namespace diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 174c8fc..4ef2b65 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1449,17 +1449,19 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, // happen to be processing that implementation, fake up the g++ ?: // semantics. See LWG issue 2141 for more information on the bug. The bugs // are fixed in g++ and libstdc++ 4.9.0 (2014-04-22). - const DecltypeType *DT = DI->getType()->getAs<DecltypeType>(); - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); - if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) && - DT->isReferenceType() && - RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() && - RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") && - D->getIdentifier() && D->getIdentifier()->isStr("type") && - SemaRef.getSourceManager().isInSystemHeader(D->getBeginLoc())) - // Fold it to the (non-reference) type which g++ would have produced. - DI = SemaRef.Context.getTrivialTypeSourceInfo( - DI->getType().getNonReferenceType()); + if (SemaRef.getPreprocessor().NeedsStdLibCxxWorkaroundBefore(2014'04'22)) { + const DecltypeType *DT = DI->getType()->getAs<DecltypeType>(); + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); + if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) && + DT->isReferenceType() && + RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() && + RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") && + D->getIdentifier() && D->getIdentifier()->isStr("type") && + SemaRef.getSourceManager().isInSystemHeader(D->getBeginLoc())) + // Fold it to the (non-reference) type which g++ would have produced. + DI = SemaRef.Context.getTrivialTypeSourceInfo( + DI->getType().getNonReferenceType()); + } // Create the new typedef TypedefNameDecl *Typedef; |