diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib')
106 files changed, 2585 insertions, 1290 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp index 73c3f02e67a8..f7e7b73d1218 100644 --- a/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm-project/clang/lib/AST/ASTImporter.cpp @@ -3109,6 +3109,11 @@ Error ASTNodeImporter::ImportTemplateInformation( case FunctionDecl::TK_FunctionTemplate: return Error::success(); + case FunctionDecl::TK_DependentNonTemplate: + if (Expected<FunctionDecl *> InstFDOrErr = + import(FromFD->getInstantiatedFromDecl())) + ToFD->setInstantiatedFromDecl(*InstFDOrErr); + return Error::success(); case FunctionDecl::TK_MemberSpecialization: { TemplateSpecializationKind TSK = FromFD->getTemplateSpecializationKind(); diff --git a/contrib/llvm-project/clang/lib/AST/Decl.cpp b/contrib/llvm-project/clang/lib/AST/Decl.cpp index 68a9dca7d1f8..8580cc639d2d 100644 --- a/contrib/llvm-project/clang/lib/AST/Decl.cpp +++ b/contrib/llvm-project/clang/lib/AST/Decl.cpp @@ -3717,8 +3717,13 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { if (TemplateOrSpecialization.isNull()) return TK_NonTemplate; - if (TemplateOrSpecialization.is<FunctionTemplateDecl *>()) + if (const auto *ND = TemplateOrSpecialization.dyn_cast<NamedDecl *>()) { + if (isa<FunctionDecl>(ND)) + return TK_DependentNonTemplate; + assert(isa<FunctionTemplateDecl>(ND) && + "No other valid types in NamedDecl"); return TK_FunctionTemplate; + } if (TemplateOrSpecialization.is<MemberSpecializationInfo *>()) return TK_MemberSpecialization; if (TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>()) @@ -3759,15 +3764,28 @@ FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, } FunctionTemplateDecl *FunctionDecl::getDescribedFunctionTemplate() const { - return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl *>(); + return dyn_cast_or_null<FunctionTemplateDecl>( + TemplateOrSpecialization.dyn_cast<NamedDecl *>()); } -void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { +void FunctionDecl::setDescribedFunctionTemplate( + FunctionTemplateDecl *Template) { assert(TemplateOrSpecialization.isNull() && "Member function is already a specialization"); TemplateOrSpecialization = Template; } +void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) { + assert(TemplateOrSpecialization.isNull() && + "Function is already a specialization"); + TemplateOrSpecialization = FD; +} + +FunctionDecl *FunctionDecl::getInstantiatedFromDecl() const { + return dyn_cast_or_null<FunctionDecl>( + TemplateOrSpecialization.dyn_cast<NamedDecl *>()); +} + bool FunctionDecl::isImplicitlyInstantiable() const { // If the function is invalid, it can't be implicitly instantiated. if (isInvalidDecl()) diff --git a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp index 13dd6da3f24f..d12330de1500 100644 --- a/contrib/llvm-project/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm-project/clang/lib/AST/DeclBase.cpp @@ -283,8 +283,9 @@ unsigned Decl::getTemplateDepth() const { return cast<Decl>(DC)->getTemplateDepth(); } -const DeclContext *Decl::getParentFunctionOrMethod() const { - for (const DeclContext *DC = getDeclContext(); +const DeclContext *Decl::getParentFunctionOrMethod(bool LexicalParent) const { + for (const DeclContext *DC = LexicalParent ? getLexicalDeclContext() + : getDeclContext(); DC && !DC->isTranslationUnit() && !DC->isNamespace(); DC = DC->getParent()) if (DC->isFunctionOrMethod()) diff --git a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp index 6fc9a86bc3cf..c307cbe02ecf 100644 --- a/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/AST/DeclCXX.cpp @@ -2410,7 +2410,7 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const { return false; QualType ParamType = getParamDecl(0)->getType(); - if (!isa<RValueReferenceType>(ParamType)) + if (!ParamType->isRValueReferenceType()) return false; ParamType = ParamType->getPointeeType(); diff --git a/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp index 3f04d9b4073e..b041e2a67e95 100644 --- a/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp +++ b/contrib/llvm-project/clang/lib/AST/DeclPrinter.cpp @@ -1007,10 +1007,10 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { } } - if (auto *Def = D->getDefinition()) { - if (D->hasAttr<FinalAttr>()) { - Out << " final"; - } + if (D->hasDefinition()) { + if (D->hasAttr<FinalAttr>()) { + Out << " final"; + } } if (D->isCompleteDefinition()) { diff --git a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp index 40e044534f0c..cd14ff4fb970 100644 --- a/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm-project/clang/lib/AST/ExprConstant.cpp @@ -11595,9 +11595,15 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) { // conservative with the last element in structs (if it's an array), so our // current behavior is more compatible than an explicit list approach would // be. + int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays; return LVal.InvalidBase && Designator.Entries.size() == Designator.MostDerivedPathLength && Designator.MostDerivedIsArrayElement && + (Designator.isMostDerivedAnUnsizedArray() || + Designator.getMostDerivedArraySize() == 0 || + (Designator.getMostDerivedArraySize() == 1 && + StrictFlexArraysLevel < 2) || + StrictFlexArraysLevel == 0) && isDesignatorAtObjectEnd(Ctx, LVal); } diff --git a/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp b/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp index 79e9fa6ab86f..22643d4edbec 100644 --- a/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp +++ b/contrib/llvm-project/clang/lib/AST/TextNodeDumper.cpp @@ -1720,6 +1720,9 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { } } + if (!D->isInlineSpecified() && D->isInlined()) { + OS << " implicit-inline"; + } // Since NumParams comes from the FunctionProtoType of the FunctionDecl and // the Params are set later, it is possible for a dump during debugging to // encounter a FunctionDecl that has been created but hasn't been assigned diff --git a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index cd87e87a6aca..5105999741e6 100644 --- a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -14,7 +14,9 @@ #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/AST/ExprCXX.h" +#include "clang/Analysis/FlowSensitive/DebugSupport.h" #include "clang/Analysis/FlowSensitive/Value.h" +#include "llvm/Support/Debug.h" #include <cassert> #include <memory> #include <utility> @@ -293,6 +295,17 @@ BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache( return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache); } +void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) { + llvm::DenseSet<BoolValue *> Constraints = {&Token}; + llvm::DenseSet<AtomicBoolValue *> VisitedTokens; + addTransitiveFlowConditionConstraints(Token, Constraints, VisitedTokens); + + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = { + {&getBoolLiteralValue(false), "False"}, + {&getBoolLiteralValue(true), "True"}}; + llvm::dbgs() << debugString(Constraints, AtomNames); +} + } // namespace dataflow } // namespace clang diff --git a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 3aea670f20aa..2b6cd0c4f857 100644 --- a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -15,10 +15,8 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/ExprCXX.h" #include "clang/AST/Type.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" -#include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -512,5 +510,9 @@ bool Environment::flowConditionImplies(BoolValue &Val) const { return DACtx->flowConditionImplies(*FlowConditionToken, Val); } +void Environment::dump() const { + DACtx->dumpFlowCondition(*FlowConditionToken); +} + } // namespace dataflow } // namespace clang diff --git a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp index 305d9d346089..309ff0682f50 100644 --- a/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp +++ b/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/DebugSupport.cpp @@ -17,6 +17,7 @@ #include "clang/Analysis/FlowSensitive/Solver.h" #include "clang/Analysis/FlowSensitive/Value.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatAdapters.h" @@ -30,6 +31,28 @@ using llvm::AlignStyle; using llvm::fmt_pad; using llvm::formatv; +std::string debugString(Solver::Result::Assignment Assignment) { + switch (Assignment) { + case Solver::Result::Assignment::AssignedFalse: + return "False"; + case Solver::Result::Assignment::AssignedTrue: + return "True"; + } + llvm_unreachable("Booleans can only be assigned true/false"); +} + +std::string debugString(Solver::Result::Status Status) { + switch (Status) { + case Solver::Result::Status::Satisfiable: + return "Satisfiable"; + case Solver::Result::Status::Unsatisfiable: + return "Unsatisfiable"; + case Solver::Result::Status::TimedOut: + return "TimedOut"; + } + llvm_unreachable("Unhandled SAT check result status"); +} + namespace { class DebugStringGenerator { @@ -80,9 +103,25 @@ public: return formatv("{0}", fmt_pad(S, Indent, 0)); } + std::string debugString(const llvm::DenseSet<BoolValue *> &Constraints) { + std::vector<std::string> ConstraintsStrings; + ConstraintsStrings.reserve(Constraints.size()); + for (BoolValue *Constraint : Constraints) { + ConstraintsStrings.push_back(debugString(*Constraint)); + } + llvm::sort(ConstraintsStrings); + + std::string Result; + for (const std::string &S : ConstraintsStrings) { + Result += S; + Result += '\n'; + } + return Result; + } + /// Returns a string representation of a set of boolean `Constraints` and the /// `Result` of satisfiability checking on the `Constraints`. - std::string debugString(const std::vector<BoolValue *> &Constraints, + std::string debugString(ArrayRef<BoolValue *> &Constraints, const Solver::Result &Result) { auto Template = R"( Constraints @@ -101,10 +140,9 @@ Constraints ConstraintsStrings.push_back(debugString(*Constraint)); } - auto StatusString = debugString(Result.getStatus()); + auto StatusString = clang::dataflow::debugString(Result.getStatus()); auto Solution = Result.getSolution(); - auto SolutionString = - Solution.hasValue() ? "\n" + debugString(Solution.value()) : ""; + auto SolutionString = Solution ? "\n" + debugString(Solution.value()) : ""; return formatv( Template, @@ -127,38 +165,14 @@ private: auto Line = formatv("{0} = {1}", fmt_align(getAtomName(AtomAssignment.first), AlignStyle::Left, MaxNameLength), - debugString(AtomAssignment.second)); + clang::dataflow::debugString(AtomAssignment.second)); Lines.push_back(Line); } - llvm::sort(Lines.begin(), Lines.end()); + llvm::sort(Lines); return formatv("{0:$[\n]}", llvm::make_range(Lines.begin(), Lines.end())); } - /// Returns a string representation of a boolean assignment to true or false. - std::string debugString(Solver::Result::Assignment Assignment) { - switch (Assignment) { - case Solver::Result::Assignment::AssignedFalse: - return "False"; - case Solver::Result::Assignment::AssignedTrue: - return "True"; - } - llvm_unreachable("Booleans can only be assigned true/false"); - } - - /// Returns a string representation of the result status of a SAT check. - std::string debugString(Solver::Result::Status Status) { - switch (Status) { - case Solver::Result::Status::Satisfiable: - return "Satisfiable"; - case Solver::Result::Status::Unsatisfiable: - return "Unsatisfiable"; - case Solver::Result::Status::TimedOut: - return "TimedOut"; - } - llvm_unreachable("Unhandled SAT check result status"); - } - /// Returns the name assigned to `Atom`, either user-specified or created by /// default rules (B0, B1, ...). std::string getAtomName(const AtomicBoolValue *Atom) { @@ -186,8 +200,13 @@ debugString(const BoolValue &B, } std::string -debugString(const std::vector<BoolValue *> &Constraints, - const Solver::Result &Result, +debugString(const llvm::DenseSet<BoolValue *> &Constraints, + llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) { + return DebugStringGenerator(std::move(AtomNames)).debugString(Constraints); +} + +std::string +debugString(ArrayRef<BoolValue *> Constraints, const Solver::Result &Result, llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) { return DebugStringGenerator(std::move(AtomNames)) .debugString(Constraints, Result); diff --git a/contrib/llvm-project/clang/lib/Analysis/ThreadSafety.cpp b/contrib/llvm-project/clang/lib/Analysis/ThreadSafety.cpp index 03bbf078d7e8..32d950864ce7 100644 --- a/contrib/llvm-project/clang/lib/Analysis/ThreadSafety.cpp +++ b/contrib/llvm-project/clang/lib/Analysis/ThreadSafety.cpp @@ -1679,6 +1679,17 @@ void BuildLockset::checkAccess(const Expr *Exp, AccessKind AK, return; } + if (const auto *BO = dyn_cast<BinaryOperator>(Exp)) { + switch (BO->getOpcode()) { + case BO_PtrMemD: // .* + return checkAccess(BO->getLHS(), AK, POK); + case BO_PtrMemI: // ->* + return checkPtAccess(BO->getLHS(), AK, POK); + default: + return; + } + } + if (const auto *AE = dyn_cast<ArraySubscriptExpr>(Exp)) { checkPtAccess(AE->getLHS(), AK, POK); return; diff --git a/contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp b/contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp index 37838f7bbc7b..4ddfcc350410 100644 --- a/contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp +++ b/contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp @@ -32,4 +32,4 @@ void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) { Res.push_back(Target[i]); } -}
\ No newline at end of file +} diff --git a/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp b/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp index 3efd613b0d33..e7e63c1f419e 100644 --- a/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp +++ b/contrib/llvm-project/clang/lib/Basic/NoSanitizeList.cpp @@ -47,6 +47,11 @@ bool NoSanitizeList::containsFile(SanitizerMask Mask, StringRef FileName, return SSCL->inSection(Mask, "src", FileName, Category); } +bool NoSanitizeList::containsMainFile(SanitizerMask Mask, StringRef FileName, + StringRef Category) const { + return SSCL->inSection(Mask, "mainfile", FileName, Category); +} + bool NoSanitizeList::containsLocation(SanitizerMask Mask, SourceLocation Loc, StringRef Category) const { return Loc.isValid() && diff --git a/contrib/llvm-project/clang/lib/Basic/Sarif.cpp b/contrib/llvm-project/clang/lib/Basic/Sarif.cpp new file mode 100644 index 000000000000..faca9c508c08 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/Sarif.cpp @@ -0,0 +1,389 @@ +//===-- clang/Basic/Sarif.cpp - SarifDocumentWriter class definition ------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declaration of the SARIFDocumentWriter class, and +/// associated builders such as: +/// - \ref SarifArtifact +/// - \ref SarifArtifactLocation +/// - \ref SarifRule +/// - \ref SarifResult +//===----------------------------------------------------------------------===// +#include "clang/Basic/Sarif.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/Path.h" + +#include <string> +#include <utility> + +using namespace clang; +using namespace llvm; + +using clang::detail::SarifArtifact; +using clang::detail::SarifArtifactLocation; + +static StringRef getFileName(const FileEntry &FE) { + StringRef Filename = FE.tryGetRealPathName(); + if (Filename.empty()) + Filename = FE.getName(); + return Filename; +} +/// \name URI +/// @{ + +/// \internal +/// \brief +/// Return the RFC3986 encoding of the input character. +/// +/// \param C Character to encode to RFC3986. +/// +/// \return The RFC3986 representation of \c C. +static std::string percentEncodeURICharacter(char C) { + // RFC 3986 claims alpha, numeric, and this handful of + // characters are not reserved for the path component and + // should be written out directly. Otherwise, percent + // encode the character and write that out instead of the + // reserved character. + if (llvm::isAlnum(C) || + StringRef::npos != StringRef("-._~:@!$&'()*+,;=").find(C)) + return std::string(&C, 1); + return "%" + llvm::toHex(StringRef(&C, 1)); +} + +/// \internal +/// \brief Return a URI representing the given file name. +/// +/// \param Filename The filename to be represented as URI. +/// +/// \return RFC3986 URI representing the input file name. +static std::string fileNameToURI(StringRef Filename) { + SmallString<32> Ret = StringRef("file://"); + + // Get the root name to see if it has a URI authority. + StringRef Root = sys::path::root_name(Filename); + if (Root.startswith("//")) { + // There is an authority, so add it to the URI. + Ret += Root.drop_front(2).str(); + } else if (!Root.empty()) { + // There is no authority, so end the component and add the root to the URI. + Ret += Twine("/" + Root).str(); + } + + auto Iter = sys::path::begin(Filename), End = sys::path::end(Filename); + assert(Iter != End && "Expected there to be a non-root path component."); + // Add the rest of the path components, encoding any reserved characters; + // we skip past the first path component, as it was handled it above. + std::for_each(++Iter, End, [&Ret](StringRef Component) { + // For reasons unknown to me, we may get a backslash with Windows native + // paths for the initial backslash following the drive component, which + // we need to ignore as a URI path part. + if (Component == "\\") + return; + + // Add the separator between the previous path part and the one being + // currently processed. + Ret += "/"; + + // URI encode the part. + for (char C : Component) { + Ret += percentEncodeURICharacter(C); + } + }); + + return std::string(Ret); +} +/// @} + +/// \brief Calculate the column position expressed in the number of UTF-8 code +/// points from column start to the source location +/// +/// \param Loc The source location whose column needs to be calculated. +/// \param TokenLen Optional hint for when the token is multiple bytes long. +/// +/// \return The column number as a UTF-8 aware byte offset from column start to +/// the effective source location. +static unsigned int adjustColumnPos(FullSourceLoc Loc, + unsigned int TokenLen = 0) { + assert(!Loc.isInvalid() && "invalid Loc when adjusting column position"); + + std::pair<FileID, unsigned> LocInfo = Loc.getDecomposedLoc(); + Optional<MemoryBufferRef> Buf = + Loc.getManager().getBufferOrNone(LocInfo.first); + assert(Buf && "got an invalid buffer for the location's file"); + assert(Buf->getBufferSize() >= (LocInfo.second + TokenLen) && + "token extends past end of buffer?"); + + // Adjust the offset to be the start of the line, since we'll be counting + // Unicode characters from there until our column offset. + unsigned int Off = LocInfo.second - (Loc.getExpansionColumnNumber() - 1); + unsigned int Ret = 1; + while (Off < (LocInfo.second + TokenLen)) { + Off += getNumBytesForUTF8(Buf->getBuffer()[Off]); + Ret++; + } + + return Ret; +} + +/// \name SARIF Utilities +/// @{ + +/// \internal +json::Object createMessage(StringRef Text) { + return json::Object{{"text", Text.str()}}; +} + +/// \internal +/// \pre CharSourceRange must be a token range +static json::Object createTextRegion(const SourceManager &SM, + const CharSourceRange &R) { + FullSourceLoc FirstTokenLoc{R.getBegin(), SM}; + FullSourceLoc LastTokenLoc{R.getEnd(), SM}; + json::Object Region{{"startLine", FirstTokenLoc.getExpansionLineNumber()}, + {"startColumn", adjustColumnPos(FirstTokenLoc)}, + {"endColumn", adjustColumnPos(LastTokenLoc)}}; + if (FirstTokenLoc != LastTokenLoc) { + Region["endLine"] = LastTokenLoc.getExpansionLineNumber(); + } + return Region; +} + +static json::Object createLocation(json::Object &&PhysicalLocation, + StringRef Message = "") { + json::Object Ret{{"physicalLocation", std::move(PhysicalLocation)}}; + if (!Message.empty()) + Ret.insert({"message", createMessage(Message)}); + return Ret; +} + +static StringRef importanceToStr(ThreadFlowImportance I) { + switch (I) { + case ThreadFlowImportance::Important: + return "important"; + case ThreadFlowImportance::Essential: + return "essential"; + case ThreadFlowImportance::Unimportant: + return "unimportant"; + } + llvm_unreachable("Fully covered switch is not so fully covered"); +} + +static json::Object +createThreadFlowLocation(json::Object &&Location, + const ThreadFlowImportance &Importance) { + return json::Object{{"location", std::move(Location)}, + {"importance", importanceToStr(Importance)}}; +} +/// @} + +json::Object +SarifDocumentWriter::createPhysicalLocation(const CharSourceRange &R) { + assert(R.isValid() && + "Cannot create a physicalLocation from invalid SourceRange!"); + assert(R.isCharRange() && + "Cannot create a physicalLocation from a token range!"); + FullSourceLoc Start{R.getBegin(), SourceMgr}; + const FileEntry *FE = Start.getExpansionLoc().getFileEntry(); + assert(FE != nullptr && "Diagnostic does not exist within a valid file!"); + + const std::string &FileURI = fileNameToURI(getFileName(*FE)); + auto I = CurrentArtifacts.find(FileURI); + + if (I == CurrentArtifacts.end()) { + uint32_t Idx = static_cast<uint32_t>(CurrentArtifacts.size()); + const SarifArtifactLocation &Location = + SarifArtifactLocation::create(FileURI).setIndex(Idx); + const SarifArtifact &Artifact = SarifArtifact::create(Location) + .setRoles({"resultFile"}) + .setLength(FE->getSize()) + .setMimeType("text/plain"); + auto StatusIter = CurrentArtifacts.insert({FileURI, Artifact}); + // If inserted, ensure the original iterator points to the newly inserted + // element, so it can be used downstream. + if (StatusIter.second) + I = StatusIter.first; + } + assert(I != CurrentArtifacts.end() && "Failed to insert new artifact"); + const SarifArtifactLocation &Location = I->second.Location; + uint32_t Idx = Location.Index.value(); + return json::Object{{{"artifactLocation", json::Object{{{"index", Idx}}}}, + {"region", createTextRegion(SourceMgr, R)}}}; +} + +json::Object &SarifDocumentWriter::getCurrentTool() { + assert(!Closed && "SARIF Document is closed. " + "Need to call createRun() before using getcurrentTool!"); + + // Since Closed = false here, expect there to be at least 1 Run, anything + // else is an invalid state. + assert(!Runs.empty() && "There are no runs associated with the document!"); + + return *Runs.back().getAsObject()->get("tool")->getAsObject(); +} + +void SarifDocumentWriter::reset() { + CurrentRules.clear(); + CurrentArtifacts.clear(); +} + +void SarifDocumentWriter::endRun() { + // Exit early if trying to close a closed Document. + if (Closed) { + reset(); + return; + } + + // Since Closed = false here, expect there to be at least 1 Run, anything + // else is an invalid state. + assert(!Runs.empty() && "There are no runs associated with the document!"); + + // Flush all the rules. + json::Object &Tool = getCurrentTool(); + json::Array Rules; + for (const SarifRule &R : CurrentRules) { + json::Object Rule{ + {"name", R.Name}, + {"id", R.Id}, + {"fullDescription", json::Object{{"text", R.Description}}}}; + if (!R.HelpURI.empty()) + Rule["helpUri"] = R.HelpURI; + Rules.emplace_back(std::move(Rule)); + } + json::Object &Driver = *Tool.getObject("driver"); + Driver["rules"] = std::move(Rules); + + // Flush all the artifacts. + json::Object &Run = getCurrentRun(); + json::Array *Artifacts = Run.getArray("artifacts"); + for (const auto &Pair : CurrentArtifacts) { + const SarifArtifact &A = Pair.getValue(); + json::Object Loc{{"uri", A.Location.URI}}; + if (A.Location.Index.has_value()) { + Loc["index"] = static_cast<int64_t>(A.Location.Index.value()); + } + json::Object Artifact; + Artifact["location"] = std::move(Loc); + if (A.Length.has_value()) + Artifact["length"] = static_cast<int64_t>(A.Length.value()); + if (!A.Roles.empty()) + Artifact["roles"] = json::Array(A.Roles); + if (!A.MimeType.empty()) + Artifact["mimeType"] = A.MimeType; + if (A.Offset.has_value()) + Artifact["offset"] = A.Offset; + Artifacts->push_back(json::Value(std::move(Artifact))); + } + + // Clear, reset temporaries before next run. + reset(); + + // Mark the document as closed. + Closed = true; +} + +json::Array +SarifDocumentWriter::createThreadFlows(ArrayRef<ThreadFlow> ThreadFlows) { + json::Object Ret{{"locations", json::Array{}}}; + json::Array Locs; + for (const auto &ThreadFlow : ThreadFlows) { + json::Object PLoc = createPhysicalLocation(ThreadFlow.Range); + json::Object Loc = createLocation(std::move(PLoc), ThreadFlow.Message); + Locs.emplace_back( + createThreadFlowLocation(std::move(Loc), ThreadFlow.Importance)); + } + Ret["locations"] = std::move(Locs); + return json::Array{std::move(Ret)}; +} + +json::Object +SarifDocumentWriter::createCodeFlow(ArrayRef<ThreadFlow> ThreadFlows) { + return json::Object{{"threadFlows", createThreadFlows(ThreadFlows)}}; +} + +void SarifDocumentWriter::createRun(StringRef ShortToolName, + StringRef LongToolName, + StringRef ToolVersion) { + // Clear resources associated with a previous run. + endRun(); + + // Signify a new run has begun. + Closed = false; + + json::Object Tool{ + {"driver", + json::Object{{"name", ShortToolName}, + {"fullName", LongToolName}, + {"language", "en-US"}, + {"version", ToolVersion}, + {"informationUri", + "https://clang.llvm.org/docs/UsersManual.html"}}}}; + json::Object TheRun{{"tool", std::move(Tool)}, + {"results", {}}, + {"artifacts", {}}, + {"columnKind", "unicodeCodePoints"}}; + Runs.emplace_back(std::move(TheRun)); +} + +json::Object &SarifDocumentWriter::getCurrentRun() { + assert(!Closed && + "SARIF Document is closed. " + "Can only getCurrentRun() if document is opened via createRun(), " + "create a run first"); + + // Since Closed = false here, expect there to be at least 1 Run, anything + // else is an invalid state. + assert(!Runs.empty() && "There are no runs associated with the document!"); + return *Runs.back().getAsObject(); +} + +size_t SarifDocumentWriter::createRule(const SarifRule &Rule) { + size_t Ret = CurrentRules.size(); + CurrentRules.emplace_back(Rule); + return Ret; +} + +void SarifDocumentWriter::appendResult(const SarifResult &Result) { + size_t RuleIdx = Result.RuleIdx; + assert(RuleIdx < CurrentRules.size() && + "Trying to reference a rule that doesn't exist"); + json::Object Ret{{"message", createMessage(Result.DiagnosticMessage)}, + {"ruleIndex", static_cast<int64_t>(RuleIdx)}, + {"ruleId", CurrentRules[RuleIdx].Id}}; + if (!Result.Locations.empty()) { + json::Array Locs; + for (auto &Range : Result.Locations) { + Locs.emplace_back(createLocation(createPhysicalLocation(Range))); + } + Ret["locations"] = std::move(Locs); + } + if (!Result.ThreadFlows.empty()) + Ret["codeFlows"] = json::Array{createCodeFlow(Result.ThreadFlows)}; + json::Object &Run = getCurrentRun(); + json::Array *Results = Run.getArray("results"); + Results->emplace_back(std::move(Ret)); +} + +json::Object SarifDocumentWriter::createDocument() { + // Flush all temporaries to their destinations if needed. + endRun(); + + json::Object Doc{ + {"$schema", SchemaURI}, + {"version", SchemaVersion}, + }; + if (!Runs.empty()) + Doc["runs"] = json::Array(Runs); + return Doc; +} diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp index 50256d8e210c..80f2601b0a24 100644 --- a/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/contrib/llvm-project/clang/lib/Basic/Targets/AMDGPU.cpp @@ -250,6 +250,7 @@ bool AMDGPUTargetInfo::initFeatureMap( break; case GK_GFX940: Features["gfx940-insts"] = true; + Features["fp8-insts"] = true; LLVM_FALLTHROUGH; case GK_GFX90A: Features["gfx90a-insts"] = true; diff --git a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp index cb2cdb50e18e..7e6c0620385a 100644 --- a/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp @@ -158,8 +158,10 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version)); } - if (ISAInfo->hasExtension("m")) { + if (ISAInfo->hasExtension("m") || ISAInfo->hasExtension("zmmul")) Builder.defineMacro("__riscv_mul"); + + if (ISAInfo->hasExtension("m")) { Builder.defineMacro("__riscv_div"); Builder.defineMacro("__riscv_muldiv"); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/ABIInfo.h b/contrib/llvm-project/clang/lib/CodeGen/ABIInfo.h index 6214148adab9..fe6cc7a2b1c7 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/ABIInfo.h +++ b/contrib/llvm-project/clang/lib/CodeGen/ABIInfo.h @@ -35,10 +35,6 @@ namespace CodeGen { class CodeGenTypes; class SwiftABIInfo; -namespace swiftcall { - class SwiftAggLowering; -} - // FIXME: All of this stuff should be part of the target interface // somehow. It is currently here because it is not clear how to factor // the targets to support this, since the Targets currently live in a diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp index 8c7ee6b078f2..113c629bf9ed 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGBuiltin.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "ABIInfo.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGCall.h b/contrib/llvm-project/clang/lib/CodeGen/CGCall.h index af63e1bddd2d..59c3f304f59b 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGCall.h +++ b/contrib/llvm-project/clang/lib/CodeGen/CGCall.h @@ -22,9 +22,6 @@ #include "clang/AST/Type.h" #include "llvm/IR/Value.h" -// FIXME: Restructure so we don't have to expose so much stuff. -#include "ABIInfo.h" - namespace llvm { class Type; class Value; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGDeclCXX.cpp index de5cb913220a..949112c63cc9 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGDeclCXX.cpp @@ -618,6 +618,130 @@ void CodeGenModule::EmitCXXThreadLocalInitFunc() { CXXThreadLocals.clear(); } +/* Build the initializer for a C++20 module: + This is arranged to be run only once regardless of how many times the module + might be included transitively. This arranged by using a control variable. + + First we call any initializers for imported modules. + We then call initializers for the Global Module Fragment (if present) + We then call initializers for the current module. + We then call initializers for the Private Module Fragment (if present) +*/ + +void CodeGenModule::EmitCXXModuleInitFunc(Module *Primary) { + while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) + CXXGlobalInits.pop_back(); + + // We create the function, even if it is empty, since an importer of this + // module will refer to it unconditionally (for the current implementation + // there is no way for the importer to know that an importee does not need + // an initializer to be run). + + // Module initializers for imported modules are emitted first. + // Collect the modules that we import + SmallVector<Module *> AllImports; + // Ones that we export + for (auto I : Primary->Exports) + AllImports.push_back(I.getPointer()); + // Ones that we only import. + for (Module *M : Primary->Imports) + AllImports.push_back(M); + + SmallVector<llvm::Function *, 8> ModuleInits; + for (Module *M : AllImports) { + // No Itanium initializer in module map modules. + if (M->isModuleMapModule()) + continue; // TODO: warn of mixed use of module map modules and C++20? + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + SmallString<256> FnName; + { + llvm::raw_svector_ostream Out(FnName); + cast<ItaniumMangleContext>(getCXXABI().getMangleContext()) + .mangleModuleInitializer(M, Out); + } + assert(!GetGlobalValue(FnName.str()) && + "We should only have one use of the initializer call"); + llvm::Function *Fn = llvm::Function::Create( + FTy, llvm::Function::ExternalLinkage, FnName.str(), &getModule()); + ModuleInits.push_back(Fn); + } + AllImports.clear(); + + // Add any initializers with specified priority; this uses the same approach + // as EmitCXXGlobalInitFunc(). + if (!PrioritizedCXXGlobalInits.empty()) { + SmallVector<llvm::Function *, 8> LocalCXXGlobalInits; + llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(), + PrioritizedCXXGlobalInits.end()); + for (SmallVectorImpl<GlobalInitData>::iterator + I = PrioritizedCXXGlobalInits.begin(), + E = PrioritizedCXXGlobalInits.end(); + I != E;) { + SmallVectorImpl<GlobalInitData>::iterator PrioE = + std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp()); + + for (; I < PrioE; ++I) + ModuleInits.push_back(I->second); + } + PrioritizedCXXGlobalInits.clear(); + } + + // Now append the ones without specified priority. + for (auto F : CXXGlobalInits) + ModuleInits.push_back(F); + CXXGlobalInits.clear(); + + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + const CGFunctionInfo &FI = getTypes().arrangeNullaryFunction(); + + // We now build the initializer for this module, which has a mangled name + // as per the Itanium ABI . The action of the initializer is guarded so that + // each init is run just once (even though a module might be imported + // multiple times via nested use). + llvm::Function *Fn; + llvm::GlobalVariable *Guard = nullptr; + { + SmallString<256> InitFnName; + llvm::raw_svector_ostream Out(InitFnName); + cast<ItaniumMangleContext>(getCXXABI().getMangleContext()) + .mangleModuleInitializer(Primary, Out); + Fn = CreateGlobalInitOrCleanUpFunction( + FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false, + llvm::GlobalVariable::ExternalLinkage); + + Guard = new llvm::GlobalVariable(getModule(), Int8Ty, /*isConstant=*/false, + llvm::GlobalVariable::InternalLinkage, + llvm::ConstantInt::get(Int8Ty, 0), + InitFnName.str() + "__in_chrg"); + } + CharUnits GuardAlign = CharUnits::One(); + Guard->setAlignment(GuardAlign.getAsAlign()); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc( + Fn, ModuleInits, ConstantAddress(Guard, Int8Ty, GuardAlign)); + // We allow for the case that a module object is added to a linked binary + // without a specific call to the the initializer. This also ensure that + // implementation partition initializers are called when the partition + // is not imported as an interface. + AddGlobalCtor(Fn); + + // See the comment in EmitCXXGlobalInitFunc about OpenCL global init + // functions. + if (getLangOpts().OpenCL) { + GenKernelArgMetadata(Fn); + Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL); + } + + assert(!getLangOpts().CUDA || !getLangOpts().CUDAIsDevice || + getLangOpts().GPUAllowDeviceInit); + if (getLangOpts().HIP && getLangOpts().CUDAIsDevice) { + Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL); + Fn->addFnAttr("device-init"); + } + + ModuleInits.clear(); +} + static SmallString<128> getTransformedFileName(llvm::Module &M) { SmallString<128> FileName = llvm::sys::path::filename(M.getName()); @@ -650,7 +774,29 @@ CodeGenModule::EmitCXXGlobalInitFunc() { while (!CXXGlobalInits.empty() && !CXXGlobalInits.back()) CXXGlobalInits.pop_back(); - if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty()) + // When we import C++20 modules, we must run their initializers first. + SmallVector<llvm::Function *, 8> ModuleInits; + if (CXX20ModuleInits) + for (Module *M : ImportedModules) { + // No Itanium initializer in module map modules. + if (M->isModuleMapModule()) + continue; + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + SmallString<256> FnName; + { + llvm::raw_svector_ostream Out(FnName); + cast<ItaniumMangleContext>(getCXXABI().getMangleContext()) + .mangleModuleInitializer(M, Out); + } + assert(!GetGlobalValue(FnName.str()) && + "We should only have one use of the initializer call"); + llvm::Function *Fn = llvm::Function::Create( + FTy, llvm::Function::ExternalLinkage, FnName.str(), &getModule()); + ModuleInits.push_back(Fn); + } + + if (ModuleInits.empty() && CXXGlobalInits.empty() && + PrioritizedCXXGlobalInits.empty()) return; llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); @@ -676,6 +822,13 @@ CodeGenModule::EmitCXXGlobalInitFunc() { llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction( FTy, "_GLOBAL__I_" + getPrioritySuffix(Priority), FI); + // Prepend the module inits to the highest priority set. + if (!ModuleInits.empty()) { + for (auto F : ModuleInits) + LocalCXXGlobalInits.push_back(F); + ModuleInits.clear(); + } + for (; I < PrioE; ++I) LocalCXXGlobalInits.push_back(I->second); @@ -685,17 +838,33 @@ CodeGenModule::EmitCXXGlobalInitFunc() { PrioritizedCXXGlobalInits.clear(); } - if (getCXXABI().useSinitAndSterm() && CXXGlobalInits.empty()) + if (getCXXABI().useSinitAndSterm() && ModuleInits.empty() && + CXXGlobalInits.empty()) return; + for (auto F : CXXGlobalInits) + ModuleInits.push_back(F); + CXXGlobalInits.clear(); + // Include the filename in the symbol name. Including "sub_" matches gcc // and makes sure these symbols appear lexicographically behind the symbols // with priority emitted above. - llvm::Function *Fn = CreateGlobalInitOrCleanUpFunction( - FTy, llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())), - FI); - - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits); + llvm::Function *Fn; + if (CXX20ModuleInits && getContext().getModuleForCodeGen()) { + SmallString<256> InitFnName; + llvm::raw_svector_ostream Out(InitFnName); + cast<ItaniumMangleContext>(getCXXABI().getMangleContext()) + .mangleModuleInitializer(getContext().getModuleForCodeGen(), Out); + Fn = CreateGlobalInitOrCleanUpFunction( + FTy, llvm::Twine(InitFnName), FI, SourceLocation(), false, + llvm::GlobalVariable::ExternalLinkage); + } else + Fn = CreateGlobalInitOrCleanUpFunction( + FTy, + llvm::Twine("_GLOBAL__sub_I_", getTransformedFileName(getModule())), + FI); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, ModuleInits); AddGlobalCtor(Fn); // In OpenCL global init functions must be converted to kernels in order to @@ -718,7 +887,7 @@ CodeGenModule::EmitCXXGlobalInitFunc() { Fn->addFnAttr("device-init"); } - CXXGlobalInits.clear(); + ModuleInits.clear(); } void CodeGenModule::EmitCXXGlobalCleanUpFunc() { diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp index cbeb6c938bee..bf3dd812b9e8 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGExpr.cpp @@ -877,7 +877,8 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, /// Determine whether this expression refers to a flexible array member in a /// struct. We disable array bounds checks for such members. -static bool isFlexibleArrayMemberExpr(const Expr *E) { +static bool isFlexibleArrayMemberExpr(const Expr *E, + unsigned StrictFlexArraysLevel) { // For compatibility with existing code, we treat arrays of length 0 or // 1 as flexible array members. // FIXME: This is inconsistent with the warning code in SemaChecking. Unify @@ -886,6 +887,11 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { // FIXME: Sema doesn't treat [1] as a flexible array member if the bound // was produced by macro expansion. + if (StrictFlexArraysLevel >= 2 && CAT->getSize().ugt(0)) + return false; + // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing + // arrays to be treated as flexible-array-members, we still emit ubsan + // checks as if they are not. if (CAT->getSize().ugt(1)) return false; } else if (!isa<IncompleteArrayType>(AT)) @@ -900,8 +906,10 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) { // FIXME: Sema doesn't treat a T[1] union member as a flexible array // member, only a T[0] or T[] member gets that treatment. + // Under StrictFlexArraysLevel, obey c99+ that disallows FAM in union, see + // C11 6.7.2.1 §18 if (FD->getParent()->isUnion()) - return true; + return StrictFlexArraysLevel < 2; RecordDecl::field_iterator FI( DeclContext::decl_iterator(const_cast<FieldDecl *>(FD))); return ++FI == FD->getParent()->field_end(); @@ -954,8 +962,10 @@ llvm::Value *CodeGenFunction::LoadPassedObjectSize(const Expr *E, /// If Base is known to point to the start of an array, return the length of /// that array. Return 0 if the length cannot be determined. -static llvm::Value *getArrayIndexingBound( - CodeGenFunction &CGF, const Expr *Base, QualType &IndexedType) { +static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF, + const Expr *Base, + QualType &IndexedType, + unsigned StrictFlexArraysLevel) { // For the vector indexing extension, the bound is the number of elements. if (const VectorType *VT = Base->getType()->getAs<VectorType>()) { IndexedType = Base->getType(); @@ -966,7 +976,7 @@ static llvm::Value *getArrayIndexingBound( if (const auto *CE = dyn_cast<CastExpr>(Base)) { if (CE->getCastKind() == CK_ArrayToPointerDecay && - !isFlexibleArrayMemberExpr(CE->getSubExpr())) { + !isFlexibleArrayMemberExpr(CE->getSubExpr(), StrictFlexArraysLevel)) { IndexedType = CE->getSubExpr()->getType(); const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) @@ -993,8 +1003,11 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base, "should not be called unless adding bounds checks"); SanitizerScope SanScope(this); + const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; + QualType IndexedType; - llvm::Value *Bound = getArrayIndexingBound(*this, Base, IndexedType); + llvm::Value *Bound = + getArrayIndexingBound(*this, Base, IndexedType, StrictFlexArraysLevel); if (!Bound) return; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGObjCRuntime.h b/contrib/llvm-project/clang/lib/CodeGen/CGObjCRuntime.h index bb27c38db204..3bd981256f47 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGObjCRuntime.h +++ b/contrib/llvm-project/clang/lib/CodeGen/CGObjCRuntime.h @@ -34,7 +34,8 @@ namespace llvm { namespace clang { namespace CodeGen { - class CodeGenFunction; +class CGFunctionInfo; +class CodeGenFunction; } class FieldDecl; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp index df7e5608f8f0..05ab16668743 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGStmt.cpp @@ -2603,14 +2603,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { for (const auto *E : GS->labels()) { JumpDest Dest = getJumpDestForLabel(E->getLabel()); Transfer.push_back(Dest.getBlock()); - llvm::BlockAddress *BA = - llvm::BlockAddress::get(CurFn, Dest.getBlock()); - Args.push_back(BA); - ArgTypes.push_back(BA->getType()); - ArgElemTypes.push_back(nullptr); if (!Constraints.empty()) Constraints += ','; - Constraints += 'i'; + Constraints += "!i"; } Fallthrough = createBasicBlock("asm.fallthrough"); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CGStmtOpenMP.cpp b/contrib/llvm-project/clang/lib/CodeGen/CGStmtOpenMP.cpp index db0b2ffd3a4f..aa55cdaca5dc 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -5203,8 +5203,30 @@ void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data); } +bool isSupportedByOpenMPIRBuilder(const OMPTaskgroupDirective &T) { + return T.clauses().empty(); +} + void CodeGenFunction::EmitOMPTaskgroupDirective( const OMPTaskgroupDirective &S) { + OMPLexicalScope Scope(*this, S, OMPD_unknown); + if (CGM.getLangOpts().OpenMPIRBuilder && isSupportedByOpenMPIRBuilder(S)) { + llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); + using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; + InsertPointTy AllocaIP(AllocaInsertPt->getParent(), + AllocaInsertPt->getIterator()); + + auto BodyGenCB = [&, this](InsertPointTy AllocaIP, + InsertPointTy CodeGenIP) { + Builder.restoreIP(CodeGenIP); + EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt()); + }; + CodeGenFunction::CGCapturedStmtInfo CapStmtInfo; + if (!CapturedStmtInfo) + CapturedStmtInfo = &CapStmtInfo; + Builder.restoreIP(OMPBuilder.createTaskgroup(Builder, AllocaIP, BodyGenCB)); + return; + } auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); if (const Expr *E = S.getReductionRef()) { @@ -5230,7 +5252,6 @@ void CodeGenFunction::EmitOMPTaskgroupDirective( } CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt()); }; - OMPLexicalScope Scope(*this, S, OMPD_unknown); CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getBeginLoc()); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.cpp index 17c1c91c7e8f..5012bd822bd3 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenFunction.cpp @@ -852,7 +852,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } if (CGM.getCodeGenOpts().getProfileInstr() != CodeGenOptions::ProfileNone) - if (CGM.isProfileInstrExcluded(Fn, Loc)) + if (CGM.isFunctionBlockedFromProfileInstr(Fn, Loc)) Fn->addFnAttr(llvm::Attribute::NoProfile); unsigned Count, Offset; diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp index c372bab1eccb..101080b6fe13 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenModule.h" +#include "ABIInfo.h" #include "CGBlocks.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" @@ -32,7 +33,6 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" -#include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" @@ -58,6 +58,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" @@ -136,6 +137,13 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, GlobalsInt8PtrTy = Int8Ty->getPointerTo(DL.getDefaultGlobalsAddressSpace()); ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace(); + // Build C++20 Module initializers. + // TODO: Add Microsoft here once we know the mangling required for the + // initializers. + CXX20ModuleInits = + LangOpts.CPlusPlusModules && getCXXABI().getMangleContext().getKind() == + ItaniumMangleContext::MK_Itanium; + RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC(); if (LangOpts.ObjC) @@ -510,6 +518,9 @@ static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO, } void CodeGenModule::Release() { + Module *Primary = getContext().getModuleForCodeGen(); + if (CXX20ModuleInits && Primary && !Primary->isModuleMapModule()) + EmitModuleInitializers(Primary); EmitDeferred(); DeferredDecls.insert(EmittedDeferredDecls.begin(), EmittedDeferredDecls.end()); @@ -518,7 +529,10 @@ void CodeGenModule::Release() { applyGlobalValReplacements(); applyReplacements(); emitMultiVersionFunctions(); - EmitCXXGlobalInitFunc(); + if (CXX20ModuleInits && Primary && Primary->isInterfaceOrPartition()) + EmitCXXModuleInitFunc(Primary); + else + EmitCXXGlobalInitFunc(); EmitCXXGlobalCleanUpFunc(); registerGlobalDtorsWithAtExit(); EmitCXXThreadLocalInitFunc(); @@ -742,19 +756,22 @@ void CodeGenModule::Release() { if (CodeGenOpts.CFProtectionReturn && Target.checkCFProtectionReturnSupported(getDiags())) { // Indicate that we want to instrument return control flow protection. - getModule().addModuleFlag(llvm::Module::Override, "cf-protection-return", + getModule().addModuleFlag(llvm::Module::Min, "cf-protection-return", 1); } if (CodeGenOpts.CFProtectionBranch && Target.checkCFProtectionBranchSupported(getDiags())) { // Indicate that we want to instrument branch control flow protection. - getModule().addModuleFlag(llvm::Module::Override, "cf-protection-branch", + getModule().addModuleFlag(llvm::Module::Min, "cf-protection-branch", 1); } if (CodeGenOpts.IBTSeal) - getModule().addModuleFlag(llvm::Module::Override, "ibt-seal", 1); + getModule().addModuleFlag(llvm::Module::Min, "ibt-seal", 1); + + if (CodeGenOpts.FunctionReturnThunks) + getModule().addModuleFlag(llvm::Module::Override, "function_return_thunk_extern", 1); // Add module metadata for return address signing (ignoring // non-leaf/all) and stack tagging. These are actually turned on by function @@ -2498,6 +2515,31 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, } } +void CodeGenModule::EmitModuleInitializers(clang::Module *Primary) { + // Emit the initializers in the order that sub-modules appear in the + // source, first Global Module Fragments, if present. + if (auto GMF = Primary->getGlobalModuleFragment()) { + for (Decl *D : getContext().getModuleInitializers(GMF)) { + assert(D->getKind() == Decl::Var && "GMF initializer decl is not a var?"); + EmitTopLevelDecl(D); + } + } + // Second any associated with the module, itself. + for (Decl *D : getContext().getModuleInitializers(Primary)) { + // Skip import decls, the inits for those are called explicitly. + if (D->getKind() == Decl::Import) + continue; + EmitTopLevelDecl(D); + } + // Third any associated with the Privat eMOdule Fragment, if present. + if (auto PMF = Primary->getPrivateModuleFragment()) { + for (Decl *D : getContext().getModuleInitializers(PMF)) { + assert(D->getKind() == Decl::Var && "PMF initializer decl is not a var?"); + EmitTopLevelDecl(D); + } + } +} + void CodeGenModule::EmitModuleLinkOptions() { // Collect the set of all of the modules we want to visit to emit link // options, which is essentially the imported modules and all of their @@ -2776,16 +2818,18 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn, // NoSanitize by function name. if (NoSanitizeL.containsFunction(Kind, Fn->getName())) return true; - // NoSanitize by location. + // NoSanitize by location. Check "mainfile" prefix. + auto &SM = Context.getSourceManager(); + const FileEntry &MainFile = *SM.getFileEntryForID(SM.getMainFileID()); + if (NoSanitizeL.containsMainFile(Kind, MainFile.getName())) + return true; + + // Check "src" prefix. if (Loc.isValid()) return NoSanitizeL.containsLocation(Kind, Loc); // If location is unknown, this may be a compiler-generated function. Assume // it's located in the main file. - auto &SM = Context.getSourceManager(); - if (const auto *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { - return NoSanitizeL.containsFile(Kind, MainFile->getName()); - } - return false; + return NoSanitizeL.containsFile(Kind, MainFile.getName()); } bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, @@ -2795,8 +2839,13 @@ bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, const auto &NoSanitizeL = getContext().getNoSanitizeList(); if (NoSanitizeL.containsGlobal(Kind, GV->getName(), Category)) return true; + auto &SM = Context.getSourceManager(); + if (NoSanitizeL.containsMainFile( + Kind, SM.getFileEntryForID(SM.getMainFileID())->getName(), Category)) + return true; if (NoSanitizeL.containsLocation(Kind, Loc, Category)) return true; + // Check global type. if (!Ty.isNull()) { // Drill down the array types: if global variable of a fixed type is @@ -2840,8 +2889,8 @@ bool CodeGenModule::imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, return true; } -bool CodeGenModule::isProfileInstrExcluded(llvm::Function *Fn, - SourceLocation Loc) const { +bool CodeGenModule::isFunctionBlockedByProfileList(llvm::Function *Fn, + SourceLocation Loc) const { const auto &ProfileList = getContext().getProfileList(); // If the profile list is empty, then instrument everything. if (ProfileList.isEmpty()) @@ -2868,6 +2917,20 @@ bool CodeGenModule::isProfileInstrExcluded(llvm::Function *Fn, return ProfileList.getDefault(); } +bool CodeGenModule::isFunctionBlockedFromProfileInstr( + llvm::Function *Fn, SourceLocation Loc) const { + if (isFunctionBlockedByProfileList(Fn, Loc)) + return true; + + auto NumGroups = getCodeGenOpts().ProfileTotalFunctionGroups; + if (NumGroups > 1) { + auto Group = llvm::crc32(arrayRefFromStringRef(Fn->getName())) % NumGroups; + if (Group != getCodeGenOpts().ProfileSelectedFunctionGroup) + return true; + } + return false; +} + bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) { // Never defer when EmitAllDecls is specified. if (LangOpts.EmitAllDecls) @@ -2903,12 +2966,20 @@ bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) { // explicitly instantiated, so they should not be emitted eagerly. return false; } - if (const auto *VD = dyn_cast<VarDecl>(Global)) + if (const auto *VD = dyn_cast<VarDecl>(Global)) { if (Context.getInlineVariableDefinitionKind(VD) == ASTContext::InlineVariableDefinitionKind::WeakUnknown) // A definition of an inline constexpr static data member may change // linkage later if it's redeclared outside the class. return false; + if (CXX20ModuleInits && VD->getOwningModule() && + !VD->getOwningModule()->isModuleMapModule()) { + // For CXX20, module-owned initializers need to be deferred, since it is + // not known at this point if they will be run for the current module or + // as part of the initializer for an imported one. + return false; + } + } // If OpenMP is enabled and threadprivates must be generated like TLS, delay // codegen for global variables, because they may be marked as threadprivate. if (LangOpts.OpenMP && LangOpts.OpenMPUseTLS && @@ -6208,6 +6279,16 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { DI->EmitImportDecl(*Import); } + // For C++ standard modules we are done - we will call the module + // initializer for imported modules, and that will likewise call those for + // any imports it has. + if (CXX20ModuleInits && Import->getImportedOwningModule() && + !Import->getImportedOwningModule()->isModuleMapModule()) + break; + + // For clang C++ module map modules the initializers for sub-modules are + // emitted here. + // Find all of the submodules and emit the module initializers. llvm::SmallPtrSet<clang::Module *, 16> Visited; SmallVector<clang::Module *, 16> Stack; @@ -6892,3 +6973,31 @@ void CodeGenModule::printPostfixForExternalizedDecl(llvm::raw_ostream &OS, OS << getContext().getCUIDHash(); } } + +void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) { + assert(DeferredDeclsToEmit.empty() && + "Should have emitted all decls deferred to emit."); + assert(NewBuilder->DeferredDecls.empty() && + "Newly created module should not have deferred decls"); + NewBuilder->DeferredDecls = std::move(DeferredDecls); + + assert(NewBuilder->DeferredVTables.empty() && + "Newly created module should not have deferred vtables"); + NewBuilder->DeferredVTables = std::move(DeferredVTables); + + assert(NewBuilder->MangledDeclNames.empty() && + "Newly created module should not have mangled decl names"); + assert(NewBuilder->Manglings.empty() && + "Newly created module should not have manglings"); + NewBuilder->Manglings = std::move(Manglings); + + assert(WeakRefReferences.empty() && "Not all WeakRefRefs have been applied"); + NewBuilder->WeakRefReferences = std::move(WeakRefReferences); + + NewBuilder->TBAA = std::move(TBAA); + + assert(NewBuilder->EmittedDeferredDecls.empty() && + "Still have (unmerged) EmittedDeferredDecls deferred decls"); + + NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls); +} diff --git a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.h index 10b49da27dab..c939e7a309f5 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm-project/clang/lib/CodeGen/CodeGenModule.h @@ -303,7 +303,7 @@ private: std::unique_ptr<CGCXXABI> ABI; llvm::LLVMContext &VMContext; std::string ModuleNameHash; - + bool CXX20ModuleInits = false; std::unique_ptr<CodeGenTBAA> TBAA; mutable std::unique_ptr<TargetCodeGenInfo> TheTargetCodeGenInfo; @@ -1340,9 +1340,15 @@ public: bool imbueXRayAttrs(llvm::Function *Fn, SourceLocation Loc, StringRef Category = StringRef()) const; - /// Returns true if function at the given location should be excluded from - /// profile instrumentation. - bool isProfileInstrExcluded(llvm::Function *Fn, SourceLocation Loc) const; + /// \returns true if \p Fn at \p Loc should be excluded from profile + /// instrumentation by the SCL passed by \p -fprofile-list. + bool isFunctionBlockedByProfileList(llvm::Function *Fn, + SourceLocation Loc) const; + + /// \returns true if \p Fn at \p Loc should be excluded from profile + /// instrumentation. + bool isFunctionBlockedFromProfileInstr(llvm::Function *Fn, + SourceLocation Loc) const; SanitizerMetadata *getSanitizerMetadata() { return SanitizerMD.get(); @@ -1508,34 +1514,7 @@ public: /// Move some lazily-emitted states to the NewBuilder. This is especially /// essential for the incremental parsing environment like Clang Interpreter, /// because we'll lose all important information after each repl. - void moveLazyEmissionStates(CodeGenModule *NewBuilder) { - assert(DeferredDeclsToEmit.empty() && - "Should have emitted all decls deferred to emit."); - assert(NewBuilder->DeferredDecls.empty() && - "Newly created module should not have deferred decls"); - NewBuilder->DeferredDecls = std::move(DeferredDecls); - - assert(NewBuilder->DeferredVTables.empty() && - "Newly created module should not have deferred vtables"); - NewBuilder->DeferredVTables = std::move(DeferredVTables); - - assert(NewBuilder->MangledDeclNames.empty() && - "Newly created module should not have mangled decl names"); - assert(NewBuilder->Manglings.empty() && - "Newly created module should not have manglings"); - NewBuilder->Manglings = std::move(Manglings); - - assert(WeakRefReferences.empty() && - "Not all WeakRefRefs have been applied"); - NewBuilder->WeakRefReferences = std::move(WeakRefReferences); - - NewBuilder->TBAA = std::move(TBAA); - - assert(NewBuilder->EmittedDeferredDecls.empty() && - "Still have (unmerged) EmittedDeferredDecls deferred decls"); - - NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls); - } + void moveLazyEmissionStates(CodeGenModule *NewBuilder); private: llvm::Constant *GetOrCreateLLVMFunction( @@ -1593,6 +1572,9 @@ private: /// Emit the function that initializes C++ thread_local variables. void EmitCXXThreadLocalInitFunc(); + /// Emit the function that initializes global variables for a C++ Module. + void EmitCXXModuleInitFunc(clang::Module *Primary); + /// Emit the function that initializes C++ globals. void EmitCXXGlobalInitFunc(); @@ -1660,6 +1642,9 @@ private: /// Emit the llvm.used and llvm.compiler.used metadata. void emitLLVMUsed(); + /// For C++20 Itanium ABI, emit the initializers for the module. + void EmitModuleInitializers(clang::Module *Primary); + /// Emit the link options introduced by imported modules. void EmitModuleLinkOptions(); diff --git a/contrib/llvm-project/clang/lib/CodeGen/SwiftCallingConv.cpp b/contrib/llvm-project/clang/lib/CodeGen/SwiftCallingConv.cpp index 1d712f4fde3c..8fb24fcecf53 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/SwiftCallingConv.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/SwiftCallingConv.cpp @@ -11,9 +11,10 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGen/SwiftCallingConv.h" -#include "clang/Basic/TargetInfo.h" +#include "ABIInfo.h" #include "CodeGenModule.h" #include "TargetInfo.h" +#include "clang/Basic/TargetInfo.h" using namespace clang; using namespace CodeGen; diff --git a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp index 8eaed1db8e7d..d1ee61eab9d6 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.cpp @@ -35,7 +35,7 @@ #include "llvm/IR/Type.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> // std::sort +#include <algorithm> using namespace clang; using namespace CodeGen; @@ -443,6 +443,9 @@ static Address emitMergePHI(CodeGenFunction &CGF, return Address(PHI, Addr1.getElementType(), Align); } +TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info) + : Info(std::move(Info)) {} + TargetCodeGenInfo::~TargetCodeGenInfo() = default; // If someone can figure out a general rule for this, that would be great. @@ -10446,6 +10449,15 @@ ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const { LTy = llvm::PointerType::getWithSamePointeeType(PtrTy, GlobalAS); return ABIArgInfo::getDirect(LTy, 0, nullptr, false); } + + // Force copying aggregate type in kernel arguments by value when + // compiling CUDA targeting SPIR-V. This is required for the object + // copied to be valid on the device. + // This behavior follows the CUDA spec + // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#global-function-argument-processing, + // and matches the NVPTX implementation. + if (isAggregateTypeForABI(Ty)) + return getNaturalAlignIndirect(Ty, /* byval */ true); } return classifyArgumentType(Ty); } diff --git a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h index bdd64977b475..30421612015b 100644 --- a/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h +++ b/contrib/llvm-project/clang/lib/CodeGen/TargetInfo.h @@ -43,10 +43,10 @@ class CGBlockInfo; /// codegeneration issues, like target-specific attributes, builtins and so /// on. class TargetCodeGenInfo { - std::unique_ptr<ABIInfo> Info = nullptr; + std::unique_ptr<ABIInfo> Info; public: - TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info) : Info(std::move(Info)) {} + TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info); virtual ~TargetCodeGenInfo(); /// getABIInfo() - Returns ABI info helper for the target. diff --git a/contrib/llvm-project/clang/lib/Driver/Driver.cpp b/contrib/llvm-project/clang/lib/Driver/Driver.cpp index 3a8400a55741..3f29afd35971 100644 --- a/contrib/llvm-project/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Driver.cpp @@ -4432,6 +4432,11 @@ Action *Driver::BuildOffloadingActions(Compilation &C, types::ID InputType = Input.first; const Arg *InputArg = Input.second; + // The toolchain can be active for unsupported file types. + if ((Kind == Action::OFK_Cuda && !types::isCuda(InputType)) || + (Kind == Action::OFK_HIP && !types::isHIP(InputType))) + continue; + // Get the product of all bound architectures and toolchains. SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs; for (const ToolChain *TC : ToolChains) @@ -4473,6 +4478,15 @@ Action *Driver::BuildOffloadingActions(Compilation &C, } } + // Compiling HIP in non-RDC mode requires linking each action individually. + for (Action *&A : DeviceActions) { + if (A->getType() != types::TY_Object || Kind != Action::OFK_HIP || + Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) + continue; + ActionList LinkerInput = {A}; + A = C.MakeAction<LinkJobAction>(LinkerInput, types::TY_Image); + } + auto TCAndArch = TCAndArchs.begin(); for (Action *A : DeviceActions) { DDeps.add(*A, *TCAndArch->first, TCAndArch->second.data(), Kind); @@ -4486,15 +4500,27 @@ Action *Driver::BuildOffloadingActions(Compilation &C, if (offloadDeviceOnly()) return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing); + if (OffloadActions.empty()) + return HostAction; + OffloadAction::DeviceDependences DDep; if (C.isOffloadingHostKind(Action::OFK_Cuda) && !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) { - // If we are not in RDC-mode we just emit the final CUDA fatbinary for each - // translation unit without requiring any linking. + // If we are not in RDC-mode we just emit the final CUDA fatbinary for + // each translation unit without requiring any linking. Action *FatbinAction = C.MakeAction<LinkJobAction>(OffloadActions, types::TY_CUDA_FATBIN); DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_Cuda>(), nullptr, Action::OFK_Cuda); + } else if (C.isOffloadingHostKind(Action::OFK_HIP) && + !Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, + false)) { + // If we are not in RDC-mode we just emit the final HIP fatbinary for each + // translation unit, linking each input individually. + Action *FatbinAction = + C.MakeAction<LinkJobAction>(OffloadActions, types::TY_HIP_FATBIN); + DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_HIP>(), + nullptr, Action::OFK_HIP); } else { // Package all the offloading actions into a single output that can be // embedded in the host and linked. @@ -4503,6 +4529,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C, DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), nullptr, Action::OFK_None); } + OffloadAction::HostDependence HDep( *HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(), /*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps); @@ -6254,6 +6281,7 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { if (IsClCompatMode) { // Include CL and Core options. IncludedFlagsBitmask |= options::CLOption; + IncludedFlagsBitmask |= options::CLDXCOption; IncludedFlagsBitmask |= options::CoreOption; } else { ExcludedFlagsBitmask |= options::CLOption; @@ -6261,10 +6289,14 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { if (IsDXCMode()) { // Include DXC and Core options. IncludedFlagsBitmask |= options::DXCOption; + IncludedFlagsBitmask |= options::CLDXCOption; IncludedFlagsBitmask |= options::CoreOption; } else { ExcludedFlagsBitmask |= options::DXCOption; } + if (!IsClCompatMode && !IsDXCMode()) + ExcludedFlagsBitmask |= options::CLDXCOption; + return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask); } diff --git a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp index ab44ba50b5d5..ec619874ad60 100644 --- a/contrib/llvm-project/clang/lib/Driver/Multilib.cpp +++ b/contrib/llvm-project/clang/lib/Driver/Multilib.cpp @@ -267,10 +267,9 @@ bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { } // Sort multilibs by priority and select the one with the highest priority. - llvm::sort(Filtered.begin(), Filtered.end(), - [](const Multilib &a, const Multilib &b) -> bool { - return a.priority() > b.priority(); - }); + llvm::sort(Filtered, [](const Multilib &a, const Multilib &b) -> bool { + return a.priority() > b.priority(); + }); if (Filtered[0].priority() > Filtered[1].priority()) { M = Filtered[0]; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp index 5130eb9b72c1..7a4319ea680f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChain.cpp @@ -1013,6 +1013,8 @@ void ToolChain::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp index 878b84a77702..64be5fe23558 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/AIX.cpp @@ -222,11 +222,13 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); const Driver &D = getDriver(); - // Add the Clang builtin headers (<resource>/include). if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { SmallString<128> P(D.ResourceDir); - path::append(P, "/include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); + // Add the PowerPC intrinsic headers (<resource>/include/ppc_wrappers) + path::append(P, "include", "ppc_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P); + // Add the Clang builtin headers (<resource>/include) + addSystemInclude(DriverArgs, CC1Args, path::parent_path(P.str())); } // Return if -nostdlibinc is specified as a driver option. @@ -275,6 +277,8 @@ void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); return; } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp index 40f9e56b38e9..a9c13464a0d6 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Ananas.cpp @@ -71,7 +71,7 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); - } else { + } else if (!Args.hasArg(options::OPT_r)) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/lib/ld-ananas.so"); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index ca625c822d05..f9f1c7835a7a 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" +#include "../Clang.h" #include "ToolChains/CommonArgs.h" #include "clang/Basic/CharInfo.h" #include "clang/Driver/Driver.h" @@ -138,10 +139,17 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, // FreeBSD local, because ld.lld doesn't support relaxations // -mno-relax is default, unless -mrelax is specified. - if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) + if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) { Features.push_back("+relax"); - else + // -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing + // into .debug_addr, which is currently not implemented. + Arg *A; + if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None) + D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation) + << A->getAsString(Args); + } else { Features.push_back("-relax"); + } // GCC Compatibility: -mno-save-restore is default, unless -msave-restore is // specified. diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp index cd07692be358..5f1638a159d5 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -276,6 +276,8 @@ void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp index 97435f1a73de..3044c2d92d21 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.cpp @@ -956,6 +956,27 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, CmdArgs.push_back("-fprofile-update=atomic"); } + int FunctionGroups = 1; + int SelectedFunctionGroup = 0; + if (const auto *A = Args.getLastArg(options::OPT_fprofile_function_groups)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, FunctionGroups) || FunctionGroups < 1) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (const auto *A = + Args.getLastArg(options::OPT_fprofile_selected_function_group)) { + StringRef Val = A->getValue(); + if (Val.getAsInteger(0, SelectedFunctionGroup) || + SelectedFunctionGroup < 0 || SelectedFunctionGroup >= FunctionGroups) + D.Diag(diag::err_drv_invalid_int_value) << A->getAsString(Args) << Val; + } + if (FunctionGroups != 1) + CmdArgs.push_back(Args.MakeArgString("-fprofile-function-groups=" + + Twine(FunctionGroups))); + if (SelectedFunctionGroup != 0) + CmdArgs.push_back(Args.MakeArgString("-fprofile-selected-function-group=" + + Twine(SelectedFunctionGroup))); + // Leave -fprofile-dir= an unused argument unless .gcda emission is // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider // the flag used. There is no -fno-profile-dir, so the user has no @@ -1902,18 +1923,11 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); - - std::string TuneCPU; - if (Name == "native") - TuneCPU = std::string(llvm::sys::getHostCPUName()); + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); else - TuneCPU = std::string(Name); - - if (!TuneCPU.empty()) { - CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); - } + CmdArgs.push_back(A->getValue()); } AddUnalignedAccessWarning(CmdArgs); @@ -2167,18 +2181,11 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args, SetRISCVSmallDataLimit(getToolChain(), Args, CmdArgs); - std::string TuneCPU; - - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); - - Name = llvm::RISCV::resolveTuneCPUAlias(Name, Triple.isArch64Bit()); - TuneCPU = std::string(Name); - } - - if (!TuneCPU.empty()) { + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + StringRef Name = + llvm::RISCV::resolveTuneCPUAlias(A->getValue(), Triple.isArch64Bit()); CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + CmdArgs.push_back(Name.data()); } } @@ -2202,19 +2209,12 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, void Clang::AddSystemZTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { - StringRef Name = A->getValue(); - - std::string TuneCPU; - if (Name == "native") - TuneCPU = std::string(llvm::sys::getHostCPUName()); + if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { + CmdArgs.push_back("-tune-cpu"); + if (strcmp(A->getValue(), "native") == 0) + CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); else - TuneCPU = std::string(Name); - - if (!TuneCPU.empty()) { - CmdArgs.push_back("-tune-cpu"); - CmdArgs.push_back(Args.MakeArgString(TuneCPU)); - } + CmdArgs.push_back(A->getValue()); } bool HasBackchain = @@ -3490,6 +3490,7 @@ static void RenderHLSLOptions(const ArgList &Args, ArgStringList &CmdArgs, types::ID InputType) { const unsigned ForwardedArguments[] = {options::OPT_dxil_validator_version, options::OPT_D, + options::OPT_I, options::OPT_S, options::OPT_emit_llvm, options::OPT_disable_llvm_passes, @@ -3985,6 +3986,9 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); CmdArgs.push_back(A->getValue()); + if (StringRef(A->getValue()) == "sarif" || + StringRef(A->getValue()) == "SARIF") + D.Diag(diag::warn_drv_sarif_format_unstable); } if (const Arg *A = Args.getLastArg( @@ -4030,9 +4034,7 @@ static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, options::OPT_fno_spell_checking); } -enum class DwarfFissionKind { None, Split, Single }; - -static DwarfFissionKind getDebugFissionKind(const Driver &D, +DwarfFissionKind tools::getDebugFissionKind(const Driver &D, const ArgList &Args, Arg *&Arg) { Arg = Args.getLastArg(options::OPT_gsplit_dwarf, options::OPT_gsplit_dwarf_EQ, options::OPT_gno_split_dwarf); @@ -5388,9 +5390,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); - // FIXME: Handle -mtune=. - (void)Args.hasArg(options::OPT_mtune_EQ); - if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { StringRef CM = A->getValue(); if (CM == "small" || CM == "kernel" || CM == "medium" || CM == "large" || @@ -5837,12 +5836,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - if (Args.hasArg(options::OPT_funstable)) { - CmdArgs.push_back("-funstable"); - if (!Args.hasArg(options::OPT_fno_coroutines_ts)) - CmdArgs.push_back("-fcoroutines-ts"); - CmdArgs.push_back("-fmodules-ts"); - } + Args.AddLastArg(CmdArgs, options::OPT_fexperimental_library); if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); @@ -6209,6 +6203,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftime_report_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace); Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); + Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); @@ -6243,6 +6238,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, options::OPT_fno_unroll_loops); + Args.AddLastArg(CmdArgs, options::OPT_fstrict_flex_arrays_EQ); + Args.AddLastArg(CmdArgs, options::OPT_pthread); if (Args.hasFlag(options::OPT_mspeculative_load_hardening, @@ -6986,7 +6983,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fcuda-include-gpubinary"); CmdArgs.push_back(CudaDeviceInput->getFilename()); } else if (!HostOffloadingInputs.empty()) { - if (IsCuda && !IsRDCMode) { + if ((IsCuda || IsHIP) && !IsRDCMode) { assert(HostOffloadingInputs.size() == 1 && "Only one input expected"); CmdArgs.push_back("-fcuda-include-gpubinary"); CmdArgs.push_back(HostOffloadingInputs.front().getFilename()); @@ -8448,14 +8445,14 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, // Forward remarks passes to the LLVM backend in the wrapper. if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("--pass-remarks=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString(Twine("--offload-opt=-pass-remarks=") + + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("--pass-remarks-missed=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-missed=") + A->getValue())); if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("--pass-remarks-analysis=") + A->getValue())); + CmdArgs.push_back(Args.MakeArgString( + Twine("--offload-opt=-pass-remarks-analysis=") + A->getValue())); if (Args.getLastArg(options::OPT_save_temps_EQ)) CmdArgs.push_back("--save-temps"); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h index 37263efd57a5..5209c6687599 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Clang.h @@ -198,6 +198,12 @@ public: const char *LinkingOutput) const override; }; +enum class DwarfFissionKind { None, Split, Single }; + +DwarfFissionKind getDebugFissionKind(const Driver &D, + const llvm::opt::ArgList &Args, + llvm::opt::Arg *&Arg); + } // end namespace tools } // end namespace driver diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp index 501e3a382ec1..9fd0529a3297 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -117,6 +117,8 @@ void CloudABI::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp index 2b043fbeecda..681a6824dad1 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -273,8 +273,11 @@ AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, void CrossWindowsToolChain:: AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { - if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + if (GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); + } } clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp index c9e773701ac3..bada811daadf 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1141,25 +1141,38 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, SmallString<128> P(getDriver().ClangExecutable); llvm::sys::path::remove_filename(P); // 'clang' llvm::sys::path::remove_filename(P); // 'bin' + llvm::sys::path::append(P, "lib", "arc"); // 'libarclite' usually lives in the same toolchain as 'clang'. However, the // Swift open source toolchains for macOS distribute Clang without libarclite. // In that case, to allow the linker to find 'libarclite', we point to the // 'libarclite' in the XcodeDefault toolchain instead. - if (getXcodeDeveloperPath(P).empty()) { - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + if (!getVFS().exists(P)) { + auto updatePath = [&](const Arg *A) { // Try to infer the path to 'libarclite' in the toolchain from the // specified SDK path. StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue()); - if (!XcodePathForSDK.empty()) { - P = XcodePathForSDK; - llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr"); - } + if (XcodePathForSDK.empty()) + return false; + + P = XcodePathForSDK; + llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr", + "lib", "arc"); + return getVFS().exists(P); + }; + + bool updated = false; + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) + updated = updatePath(A); + + if (!updated) { + if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) + updatePath(A); } } CmdArgs.push_back("-force_load"); - llvm::sys::path::append(P, "lib", "arc", "libarclite_"); + llvm::sys::path::append(P, "libarclite_"); // Mash in the platform. if (isTargetWatchOSSimulator()) P += "watchsimulator"; @@ -2448,6 +2461,7 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( break; } } + void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CXXStdlibType Type = GetCXXStdlibType(Args); @@ -2455,6 +2469,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp index 8cfec6a6c4e0..ba901407715f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -69,7 +69,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-Bshareable"); - else { + else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp index 79e3c5cbca5f..e5451c20a00c 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -170,7 +170,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); - } else { + } else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } @@ -389,10 +389,10 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() || Triple.isPPC32()) && - D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); + D.getVFS().exists(concat(getDriver().SysRoot, "/usr/lib32/crt1.o"))) + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib32")); else - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { @@ -411,14 +411,14 @@ unsigned FreeBSD::GetDefaultDwarfVersion() const { void FreeBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void FreeBSD::addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot + "/usr/include/c++/4.2", "", "", - DriverArgs, CC1Args); + addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/usr/include/c++/4.2"), + "", "", DriverArgs, CC1Args); } void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, @@ -430,6 +430,8 @@ void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp index 03ff9fe894c8..d63c69c63b1f 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -101,7 +101,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); - if (!Args.hasArg(options::OPT_shared)) { + if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) { std::string Dyld = D.DyldPrefix; if (SanArgs.needsAsanRt() && SanArgs.needsSharedRt()) Dyld += "asan/"; @@ -417,6 +417,8 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp index ed07e710fc49..93b987c07f29 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -614,6 +614,8 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args, switch (Type) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); break; diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp index 41b7b839f3b3..9c58583bca77 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/MipsLinux.cpp @@ -112,6 +112,8 @@ void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, "Only -lc++ (aka libxx) is supported in this toolchain."); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp index 753459cb230b..38151735ee51 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NaCl.cpp @@ -308,6 +308,8 @@ void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, // if the value is libc++, and emits an error for other values. GetCXXStdlibType(Args); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); } void NaClToolChain::addLibCxxIncludePaths( diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp index d1eda14a51f0..ac90ed49b8a5 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -139,7 +139,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-Bshareable"); - } else { + } else if (!Args.hasArg(options::OPT_r)) { Args.AddAllArgs(CmdArgs, options::OPT_pie); CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld.elf_so"); diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp index 54cf3cc89caf..8b3a40606ff3 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -147,7 +147,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); - } else { + } else if (!Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); } @@ -284,7 +284,7 @@ SanitizerMask OpenBSD::getSupportedSanitizers() const { OpenBSD::OpenBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); } void OpenBSD::AddClangSystemIncludeArgs( @@ -317,13 +317,14 @@ void OpenBSD::AddClangSystemIncludeArgs( return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/usr/include"); + addExternCSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/include")); } void OpenBSD::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); + concat(getDriver().SysRoot, "/usr/include/c++/v1")); } void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, @@ -331,6 +332,8 @@ void OpenBSD::AddCXXStdlibLibArgs(const ArgList &Args, bool Profiling = Args.hasArg(options::OPT_pg); CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back(Profiling ? "-lc++abi_p" : "-lc++abi"); CmdArgs.push_back(Profiling ? "-lpthread_p" : "-lpthread"); } diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp index 1e43796be1ff..9be239262db8 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -141,6 +141,8 @@ void VEToolChain::AddCXXStdlibLibArgs(const ArgList &Args, tools::addArchSpecificRPath(*this, Args, CmdArgs); CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); CmdArgs.push_back("-lunwind"); // libc++ requires -lpthread under glibc environment diff --git a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp index c5e4d569793c..b051bff87512 100644 --- a/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/contrib/llvm-project/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -444,6 +444,8 @@ void WebAssembly::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, switch (GetCXXStdlibType(Args)) { case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); + if (Args.hasArg(options::OPT_fexperimental_library)) + CmdArgs.push_back("-lc++experimental"); CmdArgs.push_back("-lc++abi"); break; case ToolChain::CST_Libstdcxx: diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index bffa66c2d944..1a785182e363 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -303,6 +303,7 @@ public: // Skip templated functions. switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: + case FunctionDecl::TK_DependentNonTemplate: break; case FunctionDecl::TK_MemberSpecialization: case FunctionDecl::TK_FunctionTemplateSpecialization: diff --git a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp index 1cd28ab073da..651ec80d6196 100644 --- a/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp +++ b/contrib/llvm-project/clang/lib/Format/ContinuationIndenter.cpp @@ -37,7 +37,7 @@ static bool shouldIndentWrappedSelectorName(const FormatStyle &Style, // Returns the length of everything up to the first possible line break after // the ), ], } or > matching \c Tok. static unsigned getLengthToMatchingParen(const FormatToken &Tok, - const SmallVector<ParenState> &Stack) { + ArrayRef<ParenState> Stack) { // Normally whether or not a break before T is possible is calculated and // stored in T.CanBreakBefore. Braces, array initializers and text proto // messages like `key: < ... >` are an exception: a break is possible @@ -656,6 +656,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, int PPColumnCorrection = 0; if (Style.IndentPPDirectives == FormatStyle::PPDIS_AfterHash && Previous.is(tok::hash) && State.FirstIndent > 0 && + &Previous == State.Line->First && (State.Line->Type == LT_PreprocessorDirective || State.Line->Type == LT_ImportStatement)) { Spaces += State.FirstIndent; @@ -1190,6 +1191,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { break; } } + if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon, + TT_InheritanceComma)) { + return State.FirstIndent + Style.ConstructorInitializerIndentWidth; + } if ((PreviousNonComment && (PreviousNonComment->ClosesTemplateDeclaration || PreviousNonComment->ClosesRequiresClause || @@ -1264,10 +1269,6 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { Style.BreakInheritanceList == FormatStyle::BILS_AfterColon) { return CurrentState.Indent; } - if (NextNonComment->isOneOf(TT_CtorInitializerColon, TT_InheritanceColon, - TT_InheritanceComma)) { - return State.FirstIndent + Style.ConstructorInitializerIndentWidth; - } if (Previous.is(tok::r_paren) && !Current.isBinaryOperator() && !Current.isOneOf(tok::colon, tok::comment)) { return ContinuationIndent; diff --git a/contrib/llvm-project/clang/lib/Format/Format.cpp b/contrib/llvm-project/clang/lib/Format/Format.cpp index d13907faca43..2659fa2af1a7 100644 --- a/contrib/llvm-project/clang/lib/Format/Format.cpp +++ b/contrib/llvm-project/clang/lib/Format/Format.cpp @@ -1895,26 +1895,31 @@ private: void removeBraces(SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result) { const auto &SourceMgr = Env.getSourceManager(); + bool EndsWithComment = false; for (AnnotatedLine *Line : Lines) { removeBraces(Line->Children, Result); - if (!Line->Affected) - continue; - for (FormatToken *Token = Line->First; Token && !Token->Finalized; - Token = Token->Next) { - if (!Token->Optional) - continue; - assert(Token->isOneOf(tok::l_brace, tok::r_brace)); - assert(Token->Next || Token == Line->Last); - const auto Start = - Token == Line->Last || - (Token->Next->isOneOf(tok::kw_else, tok::comment) && - Token->Next->NewlinesBefore > 0) - ? Token->WhitespaceRange.getBegin() - : Token->Tok.getLocation(); - const auto Range = - CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); - cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); + if (Line->Affected) { + for (FormatToken *Token = Line->First; Token && !Token->Finalized; + Token = Token->Next) { + if (!Token->Optional) + continue; + assert(Token->isOneOf(tok::l_brace, tok::r_brace)); + assert(Token->Previous || Token == Line->First); + const FormatToken *Next = Token->Next; + assert(Next || Token == Line->Last); + const auto Start = + (!Token->Previous && EndsWithComment) || + (Next && !(Next->isOneOf(tok::kw_else, tok::comment) && + Next->NewlinesBefore > 0)) + ? Token->Tok.getLocation() + : Token->WhitespaceRange.getBegin(); + const auto Range = + CharSourceRange::getCharRange(Start, Token->Tok.getEndLoc()); + cantFail(Result.add(tooling::Replacement(SourceMgr, Range, ""))); + } } + assert(Line->Last); + EndsWithComment = Line->Last->is(tok::comment); } } }; diff --git a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp index 98c012994f45..5991cf23d5dc 100644 --- a/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp +++ b/contrib/llvm-project/clang/lib/Format/TokenAnnotator.cpp @@ -999,7 +999,8 @@ private: FormatToken *Prev = Tok->getPreviousNonComment(); if (!Prev) break; - if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept)) { + if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept) || + Prev->ClosesRequiresClause) { Tok->setType(TT_CtorInitializerColon); } else if (Prev->is(tok::kw_try)) { // Member initializer list within function try block. @@ -2317,7 +2318,15 @@ private: // After right braces, star tokens are likely to be pointers to struct, // union, or class. // struct {} *ptr; - if (PrevToken->is(tok::r_brace) && Tok.is(tok::star)) + // This by itself is not sufficient to distinguish from multiplication + // following a brace-initialized expression, as in: + // int i = int{42} * 2; + // In the struct case, the part of the struct declaration until the `{` and + // the `}` are put on separate unwrapped lines; in the brace-initialized + // case, the matching `{` is on the same unwrapped line, so check for the + // presence of the matching brace to distinguish between those. + if (PrevToken->is(tok::r_brace) && Tok.is(tok::star) && + !PrevToken->MatchingParen) return TT_PointerOrReference; // For "} &&" diff --git a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp index 97c3d86282a0..83b4f1e7991f 100644 --- a/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp +++ b/contrib/llvm-project/clang/lib/Format/UnwrappedLineParser.cpp @@ -539,7 +539,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; case tok::r_brace: if (OpeningBrace) { - if (!Style.RemoveBracesLLVM || + if (!Style.RemoveBracesLLVM || Line->InPPDirective || !OpeningBrace->isOneOf(TT_ControlStatementLBrace, TT_ElseLBrace)) { return false; } @@ -2119,6 +2119,7 @@ bool UnwrappedLineParser::tryToParseLambda() { case tok::amp: case tok::star: case tok::kw_const: + case tok::kw_constexpr: case tok::comma: case tok::less: case tok::greater: diff --git a/contrib/llvm-project/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm-project/clang/lib/Frontend/FrontendAction.cpp index ed3e314cc73b..7b07ab948f64 100644 --- a/contrib/llvm-project/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/FrontendAction.cpp @@ -414,7 +414,7 @@ static std::error_code collectModuleHeaderIncludes( // Sort header paths and make the header inclusion order deterministic // across different OSs and filesystems. - llvm::sort(Headers.begin(), Headers.end(), llvm::less_first()); + llvm::sort(Headers, llvm::less_first()); for (auto &H : Headers) { // Include this header as part of the umbrella directory. Module->addTopHeader(H.second); @@ -1205,4 +1205,3 @@ bool WrapperFrontendAction::hasCodeCompletionSupport() const { WrapperFrontendAction::WrapperFrontendAction( std::unique_ptr<FrontendAction> WrappedAction) : WrappedAction(std::move(WrappedAction)) {} - diff --git a/contrib/llvm-project/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm-project/clang/lib/Frontend/InitPreprocessor.cpp index d0360696ff9c..20bfbf144a30 100644 --- a/contrib/llvm-project/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/InitPreprocessor.cpp @@ -298,12 +298,12 @@ static void DefineFastIntType(unsigned TypeWidth, bool IsSigned, /// Get the value the ATOMIC_*_LOCK_FREE macro should have for a type with /// the specified properties. -static const char *getLockFreeValue(unsigned TypeWidth, unsigned TypeAlign, - unsigned InlineWidth) { +static const char *getLockFreeValue(unsigned TypeWidth, unsigned InlineWidth) { // Fully-aligned, power-of-2 sizes no larger than the inline // width will be inlined as lock-free operations. - if (TypeWidth == TypeAlign && (TypeWidth & (TypeWidth - 1)) == 0 && - TypeWidth <= InlineWidth) + // Note: we do not need to check alignment since _Atomic(T) is always + // appropriately-aligned in clang. + if ((TypeWidth & (TypeWidth - 1)) == 0 && TypeWidth <= InlineWidth) return "2"; // "always lock free" // We cannot be certain what operations the lib calls might be // able to implement as lock-free on future processors. @@ -829,15 +829,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.ObjCRuntime.getKind() == ObjCRuntime::ObjFW) { VersionTuple tuple = LangOpts.ObjCRuntime.getVersion(); - - unsigned minor = 0; - if (tuple.getMinor()) - minor = tuple.getMinor().value(); - - unsigned subminor = 0; - if (tuple.getSubminor()) - subminor = tuple.getSubminor().value(); - + unsigned minor = tuple.getMinor().value_or(0); + unsigned subminor = tuple.getSubminor().value_or(0); Builder.defineMacro("__OBJFW_RUNTIME_ABI__", Twine(tuple.getMajor() * 10000 + minor * 100 + subminor)); @@ -1149,7 +1142,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, #define DEFINE_LOCK_FREE_MACRO(TYPE, Type) \ Builder.defineMacro(Prefix + #TYPE "_LOCK_FREE", \ getLockFreeValue(TI.get##Type##Width(), \ - TI.get##Type##Align(), \ InlineWidthBits)); DEFINE_LOCK_FREE_MACRO(BOOL, Bool); DEFINE_LOCK_FREE_MACRO(CHAR, Char); @@ -1164,7 +1156,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DEFINE_LOCK_FREE_MACRO(LLONG, LongLong); Builder.defineMacro(Prefix + "POINTER_LOCK_FREE", getLockFreeValue(TI.getPointerWidth(0), - TI.getPointerAlign(0), InlineWidthBits)); #undef DEFINE_LOCK_FREE_MACRO }; diff --git a/contrib/llvm-project/clang/lib/Frontend/TextDiagnostic.cpp b/contrib/llvm-project/clang/lib/Frontend/TextDiagnostic.cpp index 6c0ea0cde358..ab0dbcef6534 100644 --- a/contrib/llvm-project/clang/lib/Frontend/TextDiagnostic.cpp +++ b/contrib/llvm-project/clang/lib/Frontend/TextDiagnostic.cpp @@ -815,6 +815,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, emitFilename(PLoc.getFilename(), Loc.getManager()); switch (DiagOpts->getFormat()) { + case DiagnosticOptions::SARIF: case DiagnosticOptions::Clang: if (DiagOpts->ShowLine) OS << ':' << LineNo; @@ -837,6 +838,7 @@ void TextDiagnostic::emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc, OS << ColNo; } switch (DiagOpts->getFormat()) { + case DiagnosticOptions::SARIF: case DiagnosticOptions::Clang: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::MSVC: diff --git a/contrib/llvm-project/clang/lib/Headers/__clang_cuda_intrinsics.h b/contrib/llvm-project/clang/lib/Headers/__clang_cuda_intrinsics.h index cfd5eb869e34..b87413e12a27 100644 --- a/contrib/llvm-project/clang/lib/Headers/__clang_cuda_intrinsics.h +++ b/contrib/llvm-project/clang/lib/Headers/__clang_cuda_intrinsics.h @@ -71,8 +71,8 @@ } \ inline __device__ unsigned long long __FnName( \ unsigned long long __val, __Type __offset, int __width = warpSize) { \ - return static_cast<unsigned long long>(::__FnName( \ - static_cast<unsigned long long>(__val), __offset, __width)); \ + return static_cast<unsigned long long>( \ + ::__FnName(static_cast<long long>(__val), __offset, __width)); \ } \ inline __device__ double __FnName(double __val, __Type __offset, \ int __width = warpSize) { \ @@ -139,8 +139,8 @@ __MAKE_SHUFFLES(__shfl_xor, __nvvm_shfl_bfly_i32, __nvvm_shfl_bfly_f32, 0x1f, inline __device__ unsigned long long __FnName( \ unsigned int __mask, unsigned long long __val, __Type __offset, \ int __width = warpSize) { \ - return static_cast<unsigned long long>(::__FnName( \ - __mask, static_cast<unsigned long long>(__val), __offset, __width)); \ + return static_cast<unsigned long long>( \ + ::__FnName(__mask, static_cast<long long>(__val), __offset, __width)); \ } \ inline __device__ long __FnName(unsigned int __mask, long __val, \ __Type __offset, int __width = warpSize) { \ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/emmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/emmintrin.h index 8c6aa23c1a0d..a4c458a41bcf 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/emmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/emmintrin.h @@ -36,7 +36,8 @@ #ifndef EMMINTRIN_H_ #define EMMINTRIN_H_ -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) #include <altivec.h> @@ -2261,7 +2262,7 @@ extern __inline __m128d #else #include_next <emmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* EMMINTRIN_H_ */ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mm_malloc.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mm_malloc.h index 29c1de4a83e1..65920917f3bd 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mm_malloc.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mm_malloc.h @@ -10,7 +10,8 @@ #ifndef _MM_MALLOC_H_INCLUDED #define _MM_MALLOC_H_INCLUDED -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) #include <stdlib.h> diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mmintrin.h index 6f9c137b6a09..70e8b81e11ee 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/mmintrin.h @@ -35,7 +35,8 @@ #ifndef _MMINTRIN_H_INCLUDED #define _MMINTRIN_H_INCLUDED -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) #include <altivec.h> /* The Intel API is flexible enough that we must allow aliasing with other @@ -1446,7 +1447,7 @@ extern __inline __m64 #else #include_next <mmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* _MMINTRIN_H_INCLUDED */ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/pmmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/pmmintrin.h index 889f57ae89d8..fda39edbaa22 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/pmmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/pmmintrin.h @@ -39,7 +39,8 @@ #ifndef PMMINTRIN_H_ #define PMMINTRIN_H_ -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) /* We need definitions from the SSE2 and SSE header files*/ #include <emmintrin.h> @@ -138,7 +139,7 @@ extern __inline __m128i #else #include_next <pmmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* PMMINTRIN_H_ */ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/smmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/smmintrin.h index 694d5aa06940..6fe6c8a93d9b 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/smmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/smmintrin.h @@ -29,7 +29,8 @@ #ifndef SMMINTRIN_H_ #define SMMINTRIN_H_ -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) #include <altivec.h> #include <tmmintrin.h> @@ -656,7 +657,7 @@ extern __inline __m128i #else #include_next <smmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* SMMINTRIN_H_ */ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/tmmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/tmmintrin.h index 1725eb9b8f64..6185ca1e7e71 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/tmmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/tmmintrin.h @@ -25,7 +25,8 @@ #ifndef TMMINTRIN_H_ #define TMMINTRIN_H_ -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) #include <altivec.h> @@ -446,7 +447,7 @@ extern __inline __m64 #else #include_next <tmmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* TMMINTRIN_H_ */ diff --git a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/xmmintrin.h b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/xmmintrin.h index 8bf29777b79c..ee0032ca159c 100644 --- a/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/xmmintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/ppc_wrappers/xmmintrin.h @@ -35,7 +35,8 @@ #ifndef XMMINTRIN_H_ #define XMMINTRIN_H_ -#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) +#if defined(__ppc64__) && \ + (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) /* Define four value permute mask */ #define _MM_SHUFFLE(w, x, y, z) (((w) << 6) | ((x) << 4) | ((y) << 2) | (z)) @@ -1820,7 +1821,7 @@ extern __inline void #else #include_next <xmmintrin.h> -#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ - */ +#endif /* defined(__ppc64__) && + * (defined(__linux__) || defined(__FreeBSD__) || defined(_AIX)) */ #endif /* XMMINTRIN_H_ */ diff --git a/contrib/llvm-project/clang/lib/Headers/x86gprintrin.h b/contrib/llvm-project/clang/lib/Headers/x86gprintrin.h index 01e741f1eb61..2c2fbb97c9ac 100644 --- a/contrib/llvm-project/clang/lib/Headers/x86gprintrin.h +++ b/contrib/llvm-project/clang/lib/Headers/x86gprintrin.h @@ -25,11 +25,29 @@ #include <crc32intrin.h> #endif -#define __SSC_MARK(Tag) \ - __asm__ __volatile__("mov {%%ebx, %%eax|eax, ebx}; " \ - "mov {%0, %%ebx|ebx, %0}; " \ +#if defined(__i386__) +#define __FULLBX "ebx" +#define __TMPGPR "eax" +#else +// When in 64-bit target, the 32-bit operands generate a 32-bit result, +// zero-extended to a 64-bit result in the destination general-purpose, +// It means "mov x %ebx" will clobber the higher 32 bits of rbx, so we +// should preserve the 64-bit register rbx. +#define __FULLBX "rbx" +#define __TMPGPR "rax" +#endif + +#define __MOVEGPR(__r1, __r2) "mov {%%"__r1 ", %%"__r2 "|"__r2 ", "__r1"};" + +#define __SAVE_GPRBX __MOVEGPR(__FULLBX, __TMPGPR) +#define __RESTORE_GPRBX __MOVEGPR(__TMPGPR, __FULLBX) + +#define __SSC_MARK(__Tag) \ + __asm__ __volatile__( __SAVE_GPRBX \ + "mov {%0, %%ebx|ebx, %0}; " \ ".byte 0x64, 0x67, 0x90; " \ - "mov {%%eax, %%ebx|ebx, eax};" ::"i"(Tag) \ - : "%eax"); + __RESTORE_GPRBX \ + ::"i"(__Tag) \ + : __TMPGPR ); #endif /* __X86GPRINTRIN_H */ diff --git a/contrib/llvm-project/clang/lib/Lex/Lexer.cpp b/contrib/llvm-project/clang/lib/Lex/Lexer.cpp index b3aac9df6546..a4cff403e739 100644 --- a/contrib/llvm-project/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm-project/clang/lib/Lex/Lexer.cpp @@ -1462,11 +1462,11 @@ static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { return false; } else if (LangOpts.DollarIdents && '$' == C) { return true; - } else if (LangOpts.CPlusPlus) { + } else if (LangOpts.CPlusPlus || LangOpts.C2x) { // A non-leading codepoint must have the XID_Continue property. // XIDContinueRanges doesn't contains characters also in XIDStartRanges, // so we need to check both tables. - // '_' doesn't have the XID_Continue property but is allowed in C++. + // '_' doesn't have the XID_Continue property but is allowed in C and C++. static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); static const llvm::sys::UnicodeCharSet XIDContinueChars(XIDContinueRanges); return C == '_' || XIDStartChars.contains(C) || @@ -1486,7 +1486,7 @@ static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) { if (LangOpts.AsmPreprocessor) { return false; } - if (LangOpts.CPlusPlus) { + if (LangOpts.CPlusPlus || LangOpts.C2x) { static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); // '_' doesn't have the XID_Start property but is allowed in C++. return C == '_' || XIDStartChars.contains(C); diff --git a/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp b/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp index 57e344622f25..47d6f5893e97 100644 --- a/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp +++ b/contrib/llvm-project/clang/lib/Lex/ModuleMap.cpp @@ -456,10 +456,8 @@ static bool violatesPrivateInclude(Module *RequestingModule, &Header.getModule()->Headers[Module::HK_Private], &Header.getModule()->Headers[Module::HK_PrivateTextual]}; for (auto *Hs : HeaderList) - IsPrivate |= - std::find_if(Hs->begin(), Hs->end(), [&](const Module::Header &H) { - return H.Entry == IncFileEnt; - }) != Hs->end(); + IsPrivate |= llvm::any_of( + *Hs, [&](const Module::Header &H) { return H.Entry == IncFileEnt; }); assert(IsPrivate && "inconsistent headers and roles"); } #endif diff --git a/contrib/llvm-project/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm-project/clang/lib/Lex/PPDirectives.cpp index 352e1f217819..9a8fd4391b41 100644 --- a/contrib/llvm-project/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm-project/clang/lib/Lex/PPDirectives.cpp @@ -1261,7 +1261,16 @@ void Preprocessor::HandleDirective(Token &Result) { return HandleIncludeNextDirective(SavedHash.getLocation(), Result); case tok::pp_warning: - Diag(Result, diag::ext_pp_warning_directive); + if (LangOpts.CPlusPlus) + Diag(Result, LangOpts.CPlusPlus2b + ? diag::warn_cxx2b_compat_warning_directive + : diag::ext_pp_warning_directive) + << /*C++2b*/ 1; + else + Diag(Result, LangOpts.C2x ? diag::warn_c2x_compat_warning_directive + : diag::ext_pp_warning_directive) + << /*C2x*/ 0; + return HandleUserDiagnosticDirective(Result, true); case tok::pp_ident: return HandleIdentSCCSDirective(Result); @@ -1806,22 +1815,14 @@ static void diagnoseAutoModuleImport( Preprocessor &PP, SourceLocation HashLoc, Token &IncludeTok, ArrayRef<std::pair<IdentifierInfo *, SourceLocation>> Path, SourceLocation PathEnd) { - StringRef ImportKeyword; - if (PP.getLangOpts().ObjC) - ImportKeyword = "@import"; - else if (PP.getLangOpts().ModulesTS || PP.getLangOpts().CPlusPlusModules) - ImportKeyword = "import"; - else - return; // no import syntax available - SmallString<128> PathString; for (size_t I = 0, N = Path.size(); I != N; ++I) { if (I) PathString += '.'; PathString += Path[I].first->getName(); } - int IncludeKind = 0; + int IncludeKind = 0; switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { case tok::pp_include: IncludeKind = 0; @@ -1843,12 +1844,8 @@ static void diagnoseAutoModuleImport( llvm_unreachable("unknown include directive kind"); } - CharSourceRange ReplaceRange(SourceRange(HashLoc, PathEnd), - /*IsTokenRange=*/false); - PP.Diag(HashLoc, diag::warn_auto_module_import) - << IncludeKind << PathString - << FixItHint::CreateReplacement( - ReplaceRange, (ImportKeyword + " " + PathString + ";").str()); + PP.Diag(HashLoc, diag::remark_pp_include_directive_modular_translation) + << IncludeKind << PathString; } // Given a vector of path components and a string containing the real diff --git a/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp b/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp index 04b3f0460bf3..5fca029a4266 100644 --- a/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm-project/clang/lib/Parse/ParseAST.cpp @@ -172,6 +172,29 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { for (Decl *D : S.WeakTopLevelDecls()) Consumer->HandleTopLevelDecl(DeclGroupRef(D)); + // For C++20 modules, the codegen for module initializers needs to be altered + // and to be able to use a name based on the module name. + + // At this point, we should know if we are building a non-header C++20 module. + if (S.getLangOpts().CPlusPlusModules && !S.getLangOpts().IsHeaderFile && + !S.getLangOpts().CurrentModule.empty()) { + // If we are building the module from source, then the top level module + // will be here. + Module *CodegenModule = S.getCurrentModule(); + bool Interface = true; + if (CodegenModule) + // We only use module initializers for interfaces (including partition + // implementation units). + Interface = S.currentModuleIsInterface(); + else + // If we are building the module from a PCM file, then the module can be + // found here. + CodegenModule = S.getPreprocessor().getCurrentModule(); + // If neither. then .... + assert(CodegenModule && "codegen for a module, but don't know which?"); + if (Interface) + S.getASTContext().setModuleForCodeGen(CodegenModule); + } Consumer->HandleTranslationUnit(S.getASTContext()); // Finalize the template instantiation observer chain. diff --git a/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp index 164fea6a449b..9780a0aba749 100644 --- a/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm-project/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1575,8 +1575,7 @@ public: // Sort the uses by their SourceLocations. While not strictly // guaranteed to produce them in line/column order, this will provide // a stable ordering. - llvm::sort(vec->begin(), vec->end(), - [](const UninitUse &a, const UninitUse &b) { + llvm::sort(*vec, [](const UninitUse &a, const UninitUse &b) { // Prefer a more confident report over a less confident one. if (a.getKind() != b.getKind()) return a.getKind() > b.getKind(); diff --git a/contrib/llvm-project/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm-project/clang/lib/Sema/CodeCompleteConsumer.cpp index 8e8a1be38c0f..e93be3e04dfe 100644 --- a/contrib/llvm-project/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm-project/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -515,7 +515,8 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { case CK_FunctionType: return Type; - + case CK_FunctionProtoTypeLoc: + return ProtoTypeLoc.getTypePtr(); case CK_Template: case CK_Aggregate: return nullptr; @@ -524,6 +525,13 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { llvm_unreachable("Invalid CandidateKind!"); } +const FunctionProtoTypeLoc +CodeCompleteConsumer::OverloadCandidate::getFunctionProtoTypeLoc() const { + if (Kind == CK_FunctionProtoTypeLoc) + return ProtoTypeLoc; + return FunctionProtoTypeLoc(); +} + unsigned CodeCompleteConsumer::OverloadCandidate::getNumParams() const { if (Kind == CK_Template) return Template->getTemplateParameters()->size(); @@ -597,7 +605,12 @@ CodeCompleteConsumer::OverloadCandidate::getParamDecl(unsigned N) const { if (const auto *FD = getFunction()) { if (N < FD->param_size()) return FD->getParamDecl(N); + } else if (Kind == CK_FunctionProtoTypeLoc) { + if (N < ProtoTypeLoc.getNumParams()) { + return ProtoTypeLoc.getParam(N); + } } + return nullptr; } diff --git a/contrib/llvm-project/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm-project/clang/lib/Sema/SemaCUDA.cpp index 185ccebe2717..0a49d72ba963 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaCUDA.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaCUDA.cpp @@ -714,7 +714,7 @@ void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) { // Do not promote dependent variables since the cotr/dtor/initializer are // not determined. Do it after instantiation. if (getLangOpts().CUDAIsDevice && !VD->hasAttr<CUDAConstantAttr>() && - !VD->hasAttr<CUDAConstantAttr>() && !VD->hasAttr<CUDASharedAttr>() && + !VD->hasAttr<CUDASharedAttr>() && (VD->isFileVarDecl() || VD->isStaticDataMember()) && !IsDependentVar(VD) && ((VD->isConstexpr() || VD->getType().isConstQualified()) && diff --git a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp index aed1d9befe2b..dae51d0690e6 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaChecking.cpp @@ -11883,6 +11883,9 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, /// warning if the comparison is not likely to do what the programmer intended. void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS, BinaryOperatorKind Opcode) { + if (!BinaryOperator::isEqualityOp(Opcode)) + return; + // Match and capture subexpressions such as "(float) X == 0.1". FloatingLiteral *FPLiteral; CastExpr *FPCast; @@ -11918,8 +11921,8 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS, // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. - if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen)) - if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(RightExprSansParen)) + if (auto *DRL = dyn_cast<DeclRefExpr>(LeftExprSansParen)) + if (auto *DRR = dyn_cast<DeclRefExpr>(RightExprSansParen)) if (DRL->getDecl() == DRR->getDecl()) return; @@ -15827,11 +15830,26 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { /// We avoid emitting out-of-bounds access warnings for such arrays as they are /// commonly used to emulate flexible arrays in C89 code. static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, - const NamedDecl *ND) { - if (Size != 1 || !ND) return false; + const NamedDecl *ND, + unsigned StrictFlexArraysLevel) { + if (!ND) + return false; + + if (StrictFlexArraysLevel >= 2 && Size != 0) + return false; + + if (StrictFlexArraysLevel == 1 && Size.ule(1)) + return false; + + // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing + // arrays to be treated as flexible-array-members, we still emit diagnostics + // as if they are not. Pending further discussion... + if (StrictFlexArraysLevel == 0 && Size != 1) + return false; const FieldDecl *FD = dyn_cast<FieldDecl>(ND); - if (!FD) return false; + if (!FD) + return false; // Don't consider sizes resulting from macro expansions or template argument // substitution to form C89 tail-padded arrays. @@ -15854,10 +15872,13 @@ static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, } const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext()); - if (!RD) return false; - if (RD->isUnion()) return false; + if (!RD) + return false; + if (RD->isUnion()) + return false; if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { - if (!CRD->isStandardLayout()) return false; + if (!CRD->isStandardLayout()) + return false; } // See if this is the last field decl in the record. @@ -15985,9 +16006,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, // example). In this case we have no information about whether the array // access exceeds the array bounds. However we can still diagnose an array // access which precedes the array bounds. + // + // FIXME: this check should be redundant with the IsUnboundedArray check + // above. if (BaseType->isIncompleteType()) return; + // FIXME: this check should belong to the IsTailPaddedMemberArray call + // below. llvm::APInt size = ArrayTy->getSize(); if (!size.isStrictlyPositive()) return; @@ -16020,10 +16046,9 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (AllowOnePastEnd ? index.ule(size) : index.ult(size)) return; - // Also don't warn for arrays of size 1 which are members of some - // structure. These are often used to approximate flexible arrays in C89 - // code. - if (IsTailPaddedMemberArray(*this, size, ND)) + // Also don't warn for Flexible Array Member emulation. + const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; + if (IsTailPaddedMemberArray(*this, size, ND, StrictFlexArraysLevel)) return; // Suppress the warning if the subscript expression (as identified by the diff --git a/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp index 86bad736227d..8ede7c015315 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaCodeComplete.cpp @@ -53,6 +53,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" + #include <list> #include <map> #include <string> @@ -3722,13 +3723,11 @@ static void AddOverloadAggregateChunks(const RecordDecl *RD, /// Add function overload parameter chunks to the given code completion /// string. -static void AddOverloadParameterChunks(ASTContext &Context, - const PrintingPolicy &Policy, - const FunctionDecl *Function, - const FunctionProtoType *Prototype, - CodeCompletionBuilder &Result, - unsigned CurrentArg, unsigned Start = 0, - bool InOptional = false) { +static void AddOverloadParameterChunks( + ASTContext &Context, const PrintingPolicy &Policy, + const FunctionDecl *Function, const FunctionProtoType *Prototype, + FunctionProtoTypeLoc PrototypeLoc, CodeCompletionBuilder &Result, + unsigned CurrentArg, unsigned Start = 0, bool InOptional = false) { if (!Function && !Prototype) { Result.AddChunk(CodeCompletionString::CK_CurrentParameter, "..."); return; @@ -3747,8 +3746,9 @@ static void AddOverloadParameterChunks(ASTContext &Context, if (!FirstParameter) Opt.AddChunk(CodeCompletionString::CK_Comma); // Optional sections are nested. - AddOverloadParameterChunks(Context, Policy, Function, Prototype, Opt, - CurrentArg, P, /*InOptional=*/true); + AddOverloadParameterChunks(Context, Policy, Function, Prototype, + PrototypeLoc, Opt, CurrentArg, P, + /*InOptional=*/true); Result.AddOptionalChunk(Opt.TakeString()); return; } @@ -3762,8 +3762,10 @@ static void AddOverloadParameterChunks(ASTContext &Context, // Format the placeholder string. std::string Placeholder; - if (Function) { - const ParmVarDecl *Param = Function->getParamDecl(P); + assert(P < Prototype->getNumParams()); + if (Function || PrototypeLoc) { + const ParmVarDecl *Param = + Function ? Function->getParamDecl(P) : PrototypeLoc.getParam(P); Placeholder = FormatFunctionParameter(Policy, Param); if (Param->hasDefaultArg()) Placeholder += GetDefaultValueString(Param, Context.getSourceManager(), @@ -3916,8 +3918,8 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( if (getKind() == CK_Aggregate) AddOverloadAggregateChunks(getAggregate(), Policy, Result, CurrentArg); else - AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, Result, - CurrentArg); + AddOverloadParameterChunks(S.getASTContext(), Policy, FDecl, Proto, + getFunctionProtoTypeLoc(), Result, CurrentArg); Result.AddChunk(Braced ? CodeCompletionString::CK_RightBrace : CodeCompletionString::CK_RightParen); @@ -5998,6 +6000,39 @@ ProduceSignatureHelp(Sema &SemaRef, MutableArrayRef<ResultCandidate> Candidates, return getParamType(SemaRef, Candidates, CurrentArg); } +// Given a callee expression `Fn`, if the call is through a function pointer, +// try to find the declaration of the corresponding function pointer type, +// so that we can recover argument names from it. +static FunctionProtoTypeLoc GetPrototypeLoc(Expr *Fn) { + TypeLoc Target; + if (const auto *T = Fn->getType().getTypePtr()->getAs<TypedefType>()) { + Target = T->getDecl()->getTypeSourceInfo()->getTypeLoc(); + + } else if (const auto *DR = dyn_cast<DeclRefExpr>(Fn)) { + const auto *D = DR->getDecl(); + if (const auto *const VD = dyn_cast<VarDecl>(D)) { + Target = VD->getTypeSourceInfo()->getTypeLoc(); + } + } + + if (!Target) + return {}; + + if (auto P = Target.getAs<PointerTypeLoc>()) { + Target = P.getPointeeLoc(); + } + + if (auto P = Target.getAs<ParenTypeLoc>()) { + Target = P.getInnerLoc(); + } + + if (auto F = Target.getAs<FunctionProtoTypeLoc>()) { + return F; + } + + return {}; +} + QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, SourceLocation OpenParLoc) { Fn = unwrapParenList(Fn); @@ -6079,6 +6114,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, } else { // Lastly we check whether expression's type is function pointer or // function. + + FunctionProtoTypeLoc P = GetPrototypeLoc(NakedFn); QualType T = NakedFn->getType(); if (!T->getPointeeType().isNull()) T = T->getPointeeType(); @@ -6087,8 +6124,13 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, if (!TooManyArguments(FP->getNumParams(), ArgsWithoutDependentTypes.size(), /*PartialOverloading=*/true) || - FP->isVariadic()) - Results.push_back(ResultCandidate(FP)); + FP->isVariadic()) { + if (P) { + Results.push_back(ResultCandidate(P)); + } else { + Results.push_back(ResultCandidate(FP)); + } + } } else if (auto FT = T->getAs<FunctionType>()) // No prototype and declaration, it may be a K & R style function. Results.push_back(ResultCandidate(FT)); diff --git a/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp index 5a546503cced..8d2fc5331a0d 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaDecl.cpp @@ -9411,15 +9411,27 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setLocalExternDecl(); if (getLangOpts().CPlusPlus) { + // The rules for implicit inlines changed in C++20 for methods and friends + // with an in-class definition (when such a definition is not attached to + // the global module). User-specified 'inline' overrides this (set when + // the function decl is created above). + // FIXME: We need a better way to separate C++ standard and clang modules. + bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || + !NewFD->getOwningModule() || + NewFD->getOwningModule()->isGlobalModule() || + NewFD->getOwningModule()->isModuleMapModule(); bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); isFriend = D.getDeclSpec().isFriendSpecified(); if (isFriend && !isInline && D.isFunctionDefinition()) { - // C++ [class.friend]p5 + // Pre-C++20 [class.friend]p5 // A function can be defined in a friend declaration of a // class . . . . Such a function is implicitly inline. - NewFD->setImplicitlyInline(); + // Post C++20 [class.friend]p7 + // Such a function is implicitly an inline function if it is attached + // to the global module. + NewFD->setImplicitlyInline(ImplicitInlineCXX20); } // If this is a method defined in an __interface, and is not a constructor @@ -9702,11 +9714,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && - D.isFunctionDefinition()) { - // C++ [class.mfct]p2: + D.isFunctionDefinition() && !isInline) { + // Pre C++20 [class.mfct]p2: // A member function may be defined (8.4) in its class definition, in // which case it is an inline member function (7.1.2) - NewFD->setImplicitlyInline(); + // Post C++20 [class.mfct]p1: + // If a member function is attached to the global module and is defined + // in its class definition, it is inline. + NewFD->setImplicitlyInline(ImplicitInlineCXX20); } if (SC == SC_Static && isa<CXXMethodDecl>(NewFD) && @@ -16194,7 +16209,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, ED->setIntegerTypeSourceInfo(TI); else ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); - ED->setPromotionType(ED->getIntegerType()); + QualType EnumTy = ED->getIntegerType(); + ED->setPromotionType(EnumTy->isPromotableIntegerType() + ? Context.getPromotedIntegerType(EnumTy) + : EnumTy); } } else { // struct/union New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, @@ -16816,8 +16834,11 @@ CreateNewDecl: if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) ED->setIntegerTypeSourceInfo(TI); else - ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); - ED->setPromotionType(ED->getIntegerType()); + ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); + QualType EnumTy = ED->getIntegerType(); + ED->setPromotionType(EnumTy->isPromotableIntegerType() + ? Context.getPromotedIntegerType(EnumTy) + : EnumTy); assert(ED->isComplete() && "enum with type should be complete"); } } else { diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp index 742c4828b8dc..cd5cdbde7f3f 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExpr.cpp @@ -12323,7 +12323,7 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, return S.InvalidOperands(Loc, LHS, RHS); // Check for comparisons of floating point operands using != and ==. - if (Type->hasFloatingRepresentation() && BinaryOperator::isEqualityOp(Opc)) + if (Type->hasFloatingRepresentation()) S.CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); // The result of comparisons is 'bool' in C++, 'int' in C. @@ -12933,8 +12933,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); // Check for comparisons of floating point operands using != and ==. - if (BinaryOperator::isEqualityOp(Opc) && - LHSType->hasFloatingRepresentation()) { + if (LHSType->hasFloatingRepresentation()) { assert(RHS.get()->getType()->hasFloatingRepresentation()); CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); } @@ -12968,8 +12967,7 @@ QualType Sema::CheckSizelessVectorCompareOperands(ExprResult &LHS, diagnoseTautologicalComparison(*this, Loc, LHS.get(), RHS.get(), Opc); // Check for comparisons of floating point operands using != and ==. - if (BinaryOperator::isEqualityOp(Opc) && - LHSType->hasFloatingRepresentation()) { + if (LHSType->hasFloatingRepresentation()) { assert(RHS.get()->getType()->hasFloatingRepresentation()); CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc); } @@ -15402,7 +15400,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, pty->getKind() == BuiltinType::Overload)) { auto *OE = dyn_cast<OverloadExpr>(LHSExpr); if (OE && !OE->hasTemplateKeyword() && !OE->hasExplicitTemplateArgs() && - std::any_of(OE->decls_begin(), OE->decls_end(), [](NamedDecl *ND) { + llvm::any_of(OE->decls(), [](NamedDecl *ND) { return isa<FunctionTemplateDecl>(ND); })) { Diag(OE->getQualifier() ? OE->getQualifierLoc().getBeginLoc() @@ -19723,7 +19721,6 @@ public: void VisitConstantExpr(ConstantExpr *E) { // Don't mark declarations within a ConstantExpression, as this expression // will be evaluated and folded to a value. - return; } void VisitDeclRefExpr(DeclRefExpr *E) { diff --git a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp index 11f33c7c6363..5331193de863 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaExprCXX.cpp @@ -9006,14 +9006,14 @@ Sema::BuildExprRequirement( cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint() ->getImmediatelyDeclaredConstraint(); ExprResult Constraint = SubstExpr(IDC, MLTAL); - assert(!Constraint.isInvalid() && - "Substitution cannot fail as it is simply putting a type template " - "argument into a concept specialization expression's parameter."); - - SubstitutedConstraintExpr = - cast<ConceptSpecializationExpr>(Constraint.get()); - if (!SubstitutedConstraintExpr->isSatisfied()) - Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; + if (Constraint.isInvalid()) { + Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure; + } else { + SubstitutedConstraintExpr = + cast<ConceptSpecializationExpr>(Constraint.get()); + if (!SubstitutedConstraintExpr->isSatisfied()) + Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; + } } return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc, ReturnTypeRequirement, Status, diff --git a/contrib/llvm-project/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm-project/clang/lib/Sema/SemaLookup.cpp index 47c7a61f8072..242e1f81d75c 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaLookup.cpp @@ -1615,7 +1615,10 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D, if (!D->hasDefaultArgument()) return false; - while (D) { + llvm::SmallDenseSet<const ParmDecl *, 4> Visited; + while (D && !Visited.count(D)) { + Visited.insert(D); + auto &DefaultArg = D->getDefaultArgStorage(); if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind)) return true; @@ -1625,7 +1628,8 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D, Modules->push_back(S.getOwningModule(NonConstD)); } - // If there was a previous default argument, maybe its parameter is visible. + // If there was a previous default argument, maybe its parameter is + // acceptable. D = DefaultArg.getInheritedFrom(); } return false; @@ -2087,6 +2091,13 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) { if (isVisible(SemaRef, ND)) return true; + // Deduction guide lives in namespace scope generally, but it is just a + // hint to the compilers. What we actually lookup for is the generated member + // of the corresponding template. So it is sufficient to check the + // reachability of the template decl. + if (auto *DeductionGuide = ND->getDeclName().getCXXDeductionGuideTemplate()) + return SemaRef.hasReachableDefinition(DeductionGuide); + auto *DC = ND->getDeclContext(); // If ND is not visible and it is at namespace scope, it shouldn't be found // by name lookup. diff --git a/contrib/llvm-project/clang/lib/Sema/SemaModule.cpp b/contrib/llvm-project/clang/lib/Sema/SemaModule.cpp index e9a1ac17ce86..f5c24bd10daa 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaModule.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaModule.cpp @@ -344,6 +344,16 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // statements, so imports are allowed. ImportState = ModuleImportState::ImportAllowed; + // For an implementation, We already made an implicit import (its interface). + // Make and return the import decl to be added to the current TU. + if (MDK == ModuleDeclKind::Implementation) { + // Make the import decl for the interface. + ImportDecl *Import = + ImportDecl::Create(Context, CurContext, ModuleLoc, Mod, Path[0].second); + // and return it to be added. + return ConvertDeclToDeclGroup(Import); + } + // FIXME: Create a ModuleDecl. return nullptr; } diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp index 67cf8f0371c5..95c83ebfaeab 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplate.cpp @@ -2520,7 +2520,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, continue; // Cannot make a deduction guide when unparsed arguments are present. - if (std::any_of(CD->param_begin(), CD->param_end(), [](ParmVarDecl *P) { + if (llvm::any_of(CD->parameters(), [](ParmVarDecl *P) { return !P || P->hasUnparsedDefaultArg(); })) continue; @@ -4573,7 +4573,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, void *InsertPos = nullptr; if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( Converted, InsertPos)) { - checkSpecializationVisibility(TemplateNameLoc, Spec); + checkSpecializationReachability(TemplateNameLoc, Spec); // If we already have a variable template specialization, return it. return Spec; } @@ -4694,7 +4694,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) Decl->setInstantiationOf(D, InstantiationArgs); - checkSpecializationVisibility(TemplateNameLoc, Decl); + checkSpecializationReachability(TemplateNameLoc, Decl); assert(Decl && "No variable template specialization?"); return Decl; diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index bd166ff6f594..9bf6ca1f8084 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2182,6 +2182,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // definition. We don't want non-template functions to be marked as being // template instantiations. Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + } else if (!isFriend) { + // If this is not a function template, and this is not a friend (that is, + // this is a locally declared function), save the instantiation relationship + // for the purposes of constraint instantiation. + Function->setInstantiatedFromDecl(D); } if (isFriend) { diff --git a/contrib/llvm-project/clang/lib/Sema/SemaType.cpp b/contrib/llvm-project/clang/lib/Sema/SemaType.cpp index 3edce941c381..3ab5d26a9a75 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaType.cpp @@ -8669,12 +8669,13 @@ bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, // of it will do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { - if (isVisible(Redecl)) + if (isAcceptable(Redecl, Kind)) return true; if (Redecl->isThisDeclarationADefinition() || (Redecl->isCanonicalDecl() && !*Suggested)) *Suggested = Redecl; } + return false; } D = ED->getDefinition(); diff --git a/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp index 04ade0a3b9d0..76281d26b2ae 100644 --- a/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm-project/clang/lib/Serialization/ASTReader.cpp @@ -9445,6 +9445,31 @@ void ASTReader::finishPendingActions() { PendingMergedDefinitionsToDeduplicate.clear(); } +static unsigned computeODRHash(QualType Ty) { + ODRHash Hasher; + Hasher.AddQualType(Ty); + return Hasher.CalculateHash(); +} + +static unsigned computeODRHash(const Stmt *S) { + ODRHash Hasher; + Hasher.AddStmt(S); + return Hasher.CalculateHash(); +} + +static unsigned computeODRHash(const Decl *D) { + assert(D); + ODRHash Hasher; + Hasher.AddSubDecl(D); + return Hasher.CalculateHash(); +} + +static unsigned computeODRHash(const TemplateArgument &TA) { + ODRHash Hasher; + Hasher.AddTemplateArgument(TA); + return Hasher.CalculateHash(); +} + void ASTReader::diagnoseOdrViolations() { if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() && PendingFunctionOdrMergeFailures.empty() && @@ -9584,42 +9609,6 @@ void ASTReader::diagnoseOdrViolations() { // we're producing our diagnostics. Deserializing RecursionGuard(this); - // Common code for hashing helpers. - ODRHash Hash; - auto ComputeQualTypeODRHash = [&Hash](QualType Ty) { - Hash.clear(); - Hash.AddQualType(Ty); - return Hash.CalculateHash(); - }; - - auto ComputeODRHash = [&Hash](const Stmt *S) { - assert(S); - Hash.clear(); - Hash.AddStmt(S); - return Hash.CalculateHash(); - }; - - auto ComputeSubDeclODRHash = [&Hash](const Decl *D) { - assert(D); - Hash.clear(); - Hash.AddSubDecl(D); - return Hash.CalculateHash(); - }; - - auto ComputeTemplateArgumentODRHash = [&Hash](const TemplateArgument &TA) { - Hash.clear(); - Hash.AddTemplateArgument(TA); - return Hash.CalculateHash(); - }; - - auto ComputeTemplateParameterListODRHash = - [&Hash](const TemplateParameterList *TPL) { - assert(TPL); - Hash.clear(); - Hash.AddTemplateParameterList(TPL); - return Hash.CalculateHash(); - }; - // Used with err_module_odr_violation_mismatch_decl and // note_module_odr_violation_mismatch_decl // This list should be the same Decl's as in ODRHash::isDeclToBeProcessed @@ -9639,49 +9628,13 @@ void ASTReader::diagnoseOdrViolations() { Other }; - // Used with err_module_odr_violation_record and - // note_module_odr_violation_record - enum ODRCXXRecordDifference { - StaticAssertCondition, - StaticAssertMessage, - StaticAssertOnlyMessage, - MethodName, - MethodDeleted, - MethodDefaulted, - MethodVirtual, - MethodStatic, - MethodVolatile, - MethodConst, - MethodInline, - MethodNumberParameters, - MethodParameterType, - MethodParameterName, - MethodParameterSingleDefaultArgument, - MethodParameterDifferentDefaultArgument, - MethodNoTemplateArguments, - MethodDifferentNumberTemplateArguments, - MethodDifferentTemplateArgument, - MethodSingleBody, - MethodDifferentBody, - FriendTypeFunction, - FriendType, - FriendFunction, - FunctionTemplateDifferentNumberParameters, - FunctionTemplateParameterDifferentKind, - FunctionTemplateParameterName, - FunctionTemplateParameterSingleDefaultArgument, - FunctionTemplateParameterDifferentDefaultArgument, - FunctionTemplateParameterDifferentType, - FunctionTemplatePackParameter, - }; - // These lambdas have the common portions of the ODR diagnostics. This // has the same return as Diag(), so addition parameters can be passed // in with operator<< - auto ODRDiagField = [this, &ComputeQualTypeODRHash, &ComputeODRHash]( - NamedDecl *FirstRecord, StringRef FirstModule, - StringRef SecondModule, FieldDecl *FirstField, - FieldDecl *SecondField) { + auto ODRDiagField = [this](NamedDecl *FirstRecord, StringRef FirstModule, + StringRef SecondModule, + const FieldDecl *FirstField, + const FieldDecl *SecondField) { enum ODRFieldDifference { FieldName, FieldTypeName, @@ -9719,8 +9672,7 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstType = FirstField->getType(); QualType SecondType = SecondField->getType(); - if (ComputeQualTypeODRHash(FirstType) != - ComputeQualTypeODRHash(SecondType)) { + if (computeODRHash(FirstType) != computeODRHash(SecondType)) { DiagError(FieldTypeName) << FirstII << FirstType; DiagNote(FieldTypeName) << SecondII << SecondType; return true; @@ -9735,10 +9687,8 @@ void ASTReader::diagnoseOdrViolations() { } if (IsFirstBitField && IsSecondBitField) { - unsigned FirstBitWidthHash = - ComputeODRHash(FirstField->getBitWidth()); - unsigned SecondBitWidthHash = - ComputeODRHash(SecondField->getBitWidth()); + unsigned FirstBitWidthHash = computeODRHash(FirstField->getBitWidth()); + unsigned SecondBitWidthHash = computeODRHash(SecondField->getBitWidth()); if (FirstBitWidthHash != SecondBitWidthHash) { DiagError(FieldDifferentWidthBitField) << FirstII << FirstField->getBitWidth()->getSourceRange(); @@ -9771,8 +9721,8 @@ void ASTReader::diagnoseOdrViolations() { } if (FirstInitializer && SecondInitializer) { - unsigned FirstInitHash = ComputeODRHash(FirstInitializer); - unsigned SecondInitHash = ComputeODRHash(SecondInitializer); + unsigned FirstInitHash = computeODRHash(FirstInitializer); + unsigned SecondInitHash = computeODRHash(SecondInitializer); if (FirstInitHash != SecondInitHash) { DiagError(FieldDifferentInitializers) << FirstII << FirstInitializer->getSourceRange(); @@ -9786,10 +9736,9 @@ void ASTReader::diagnoseOdrViolations() { }; auto ODRDiagTypeDefOrAlias = - [this, &ComputeQualTypeODRHash]( - NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule, - TypedefNameDecl *FirstTD, TypedefNameDecl *SecondTD, - bool IsTypeAlias) { + [this](NamedDecl *FirstRecord, StringRef FirstModule, + StringRef SecondModule, const TypedefNameDecl *FirstTD, + const TypedefNameDecl *SecondTD, bool IsTypeAlias) { enum ODRTypedefDifference { TypedefName, TypedefType, @@ -9809,8 +9758,8 @@ void ASTReader::diagnoseOdrViolations() { << SecondModule << SecondTD->getSourceRange() << DiffType; }; - auto FirstName = FirstTD->getDeclName(); - auto SecondName = SecondTD->getDeclName(); + DeclarationName FirstName = FirstTD->getDeclName(); + DeclarationName SecondName = SecondTD->getDeclName(); if (FirstName != SecondName) { DiagError(TypedefName) << IsTypeAlias << FirstName; DiagNote(TypedefName) << IsTypeAlias << SecondName; @@ -9819,8 +9768,7 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstType = FirstTD->getUnderlyingType(); QualType SecondType = SecondTD->getUnderlyingType(); - if (ComputeQualTypeODRHash(FirstType) != - ComputeQualTypeODRHash(SecondType)) { + if (computeODRHash(FirstType) != computeODRHash(SecondType)) { DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType; DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType; return true; @@ -9829,10 +9777,9 @@ void ASTReader::diagnoseOdrViolations() { return false; }; - auto ODRDiagVar = [&ComputeQualTypeODRHash, &ComputeODRHash, - this](NamedDecl *FirstRecord, StringRef FirstModule, - StringRef SecondModule, VarDecl *FirstVD, - VarDecl *SecondVD) { + auto ODRDiagVar = [this](NamedDecl *FirstRecord, StringRef FirstModule, + StringRef SecondModule, const VarDecl *FirstVD, + const VarDecl *SecondVD) { enum ODRVarDifference { VarName, VarType, @@ -9854,8 +9801,8 @@ void ASTReader::diagnoseOdrViolations() { << SecondModule << SecondVD->getSourceRange() << DiffType; }; - auto FirstName = FirstVD->getDeclName(); - auto SecondName = SecondVD->getDeclName(); + DeclarationName FirstName = FirstVD->getDeclName(); + DeclarationName SecondName = SecondVD->getDeclName(); if (FirstName != SecondName) { DiagError(VarName) << FirstName; DiagNote(VarName) << SecondName; @@ -9864,8 +9811,7 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstType = FirstVD->getType(); QualType SecondType = SecondVD->getType(); - if (ComputeQualTypeODRHash(FirstType) != - ComputeQualTypeODRHash(SecondType)) { + if (computeODRHash(FirstType) != computeODRHash(SecondType)) { DiagError(VarType) << FirstName << FirstType; DiagNote(VarType) << SecondName << SecondType; return true; @@ -9887,7 +9833,7 @@ void ASTReader::diagnoseOdrViolations() { } if (FirstInit && SecondInit && - ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + computeODRHash(FirstInit) != computeODRHash(SecondInit)) { DiagError(VarDifferentInitializer) << FirstName << FirstInit->getSourceRange(); DiagNote(VarDifferentInitializer) @@ -9905,52 +9851,13 @@ void ASTReader::diagnoseOdrViolations() { return false; }; - auto DifferenceSelector = [](Decl *D) { - assert(D && "valid Decl required"); - switch (D->getKind()) { - default: - return Other; - case Decl::AccessSpec: - switch (D->getAccess()) { - case AS_public: - return PublicSpecifer; - case AS_private: - return PrivateSpecifer; - case AS_protected: - return ProtectedSpecifer; - case AS_none: - break; - } - llvm_unreachable("Invalid access specifier"); - case Decl::StaticAssert: - return StaticAssert; - case Decl::Field: - return Field; - case Decl::CXXMethod: - case Decl::CXXConstructor: - case Decl::CXXDestructor: - return CXXMethod; - case Decl::TypeAlias: - return TypeAlias; - case Decl::Typedef: - return TypeDef; - case Decl::Var: - return Var; - case Decl::Friend: - return Friend; - case Decl::FunctionTemplate: - return FunctionTemplate; - } - }; - using DeclHashes = llvm::SmallVector<std::pair<Decl *, unsigned>, 4>; - auto PopulateHashes = [&ComputeSubDeclODRHash](DeclHashes &Hashes, - RecordDecl *Record, - const DeclContext *DC) { + auto PopulateHashes = [](DeclHashes &Hashes, RecordDecl *Record, + const DeclContext *DC) { for (auto *D : Record->decls()) { if (!ODRHash::isDeclToBeProcessed(D, DC)) continue; - Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); + Hashes.emplace_back(D, computeODRHash(D)); } }; @@ -9962,8 +9869,45 @@ void ASTReader::diagnoseOdrViolations() { // If there is a diagnoseable difference, FirstDiffType and // SecondDiffType will not be Other and FirstDecl and SecondDecl will be // filled in if not EndOfClass. - auto FindTypeDiffs = [&DifferenceSelector](DeclHashes &FirstHashes, - DeclHashes &SecondHashes) { + auto FindTypeDiffs = [](DeclHashes &FirstHashes, DeclHashes &SecondHashes) { + auto DifferenceSelector = [](Decl *D) { + assert(D && "valid Decl required"); + switch (D->getKind()) { + default: + return Other; + case Decl::AccessSpec: + switch (D->getAccess()) { + case AS_public: + return PublicSpecifer; + case AS_private: + return PrivateSpecifer; + case AS_protected: + return ProtectedSpecifer; + case AS_none: + break; + } + llvm_unreachable("Invalid access specifier"); + case Decl::StaticAssert: + return StaticAssert; + case Decl::Field: + return Field; + case Decl::CXXMethod: + case Decl::CXXConstructor: + case Decl::CXXDestructor: + return CXXMethod; + case Decl::TypeAlias: + return TypeAlias; + case Decl::Typedef: + return TypeDef; + case Decl::Var: + return Var; + case Decl::Friend: + return Friend; + case Decl::FunctionTemplate: + return FunctionTemplate; + } + }; + DiffResult DR; auto FirstIt = FirstHashes.begin(); auto SecondIt = SecondHashes.begin(); @@ -10062,19 +10006,6 @@ void ASTReader::diagnoseOdrViolations() { continue; std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord); - auto ODRDiagDeclError = [FirstRecord, &FirstModule, - this](SourceLocation Loc, SourceRange Range, - ODRCXXRecordDifference DiffType) { - return Diag(Loc, diag::err_module_odr_violation_record) - << FirstRecord << FirstModule.empty() << FirstModule << Range - << DiffType; - }; - auto ODRDiagDeclNote = [&SecondModule, - this](SourceLocation Loc, SourceRange Range, - ODRCXXRecordDifference DiffType) { - return Diag(Loc, diag::note_module_odr_violation_record) - << SecondModule << Range << DiffType; - }; auto *FirstDD = FirstRecord->DefinitionData; auto *SecondDD = RecordPair.second; @@ -10103,20 +10034,18 @@ void ASTReader::diagnoseOdrViolations() { return Diag(Loc, diag::note_module_odr_violation_definition_data) << SecondModule << Range << DiffType; }; - - unsigned FirstNumBases = FirstDD->NumBases; - unsigned FirstNumVBases = FirstDD->NumVBases; - unsigned SecondNumBases = SecondDD->NumBases; - unsigned SecondNumVBases = SecondDD->NumVBases; - auto GetSourceRange = [](struct CXXRecordDecl::DefinitionData *DD) { unsigned NumBases = DD->NumBases; if (NumBases == 0) return SourceRange(); - auto bases = DD->bases(); + ArrayRef<CXXBaseSpecifier> bases = DD->bases(); return SourceRange(bases[0].getBeginLoc(), bases[NumBases - 1].getEndLoc()); }; + unsigned FirstNumBases = FirstDD->NumBases; + unsigned FirstNumVBases = FirstDD->NumVBases; + unsigned SecondNumBases = SecondDD->NumBases; + unsigned SecondNumVBases = SecondDD->NumVBases; if (FirstNumBases != SecondNumBases) { ODRDiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD), NumBases) @@ -10139,30 +10068,30 @@ void ASTReader::diagnoseOdrViolations() { break; } - auto FirstBases = FirstDD->bases(); - auto SecondBases = SecondDD->bases(); - unsigned i = 0; - for (i = 0; i < FirstNumBases; ++i) { - auto FirstBase = FirstBases[i]; - auto SecondBase = SecondBases[i]; - if (ComputeQualTypeODRHash(FirstBase.getType()) != - ComputeQualTypeODRHash(SecondBase.getType())) { + ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases(); + ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases(); + unsigned I = 0; + for (I = 0; I < FirstNumBases; ++I) { + const CXXBaseSpecifier FirstBase = FirstBases[I]; + const CXXBaseSpecifier SecondBase = SecondBases[I]; + if (computeODRHash(FirstBase.getType()) != + computeODRHash(SecondBase.getType())) { ODRDiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), BaseType) - << (i + 1) << FirstBase.getType(); + << (I + 1) << FirstBase.getType(); ODRDiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), BaseType) - << (i + 1) << SecondBase.getType(); + << (I + 1) << SecondBase.getType(); break; } if (FirstBase.isVirtual() != SecondBase.isVirtual()) { ODRDiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), BaseVirtual) - << (i + 1) << FirstBase.isVirtual() << FirstBase.getType(); + << (I + 1) << FirstBase.isVirtual() << FirstBase.getType(); ODRDiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), BaseVirtual) - << (i + 1) << SecondBase.isVirtual() << SecondBase.getType(); + << (I + 1) << SecondBase.isVirtual() << SecondBase.getType(); break; } @@ -10170,17 +10099,17 @@ void ASTReader::diagnoseOdrViolations() { SecondBase.getAccessSpecifierAsWritten()) { ODRDiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), BaseAccess) - << (i + 1) << FirstBase.getType() + << (I + 1) << FirstBase.getType() << (int)FirstBase.getAccessSpecifierAsWritten(); ODRDiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), BaseAccess) - << (i + 1) << SecondBase.getType() + << (I + 1) << SecondBase.getType() << (int)SecondBase.getAccessSpecifierAsWritten(); break; } } - if (i != FirstNumBases) { + if (I != FirstNumBases) { Diagnosed = true; break; } @@ -10198,13 +10127,12 @@ void ASTReader::diagnoseOdrViolations() { DeclHashes FirstTemplateHashes; DeclHashes SecondTemplateHashes; - auto PopulateTemplateParameterHashs = - [&ComputeSubDeclODRHash](DeclHashes &Hashes, - const ClassTemplateDecl *TD) { - for (auto *D : TD->getTemplateParameters()->asArray()) { - Hashes.emplace_back(D, ComputeSubDeclODRHash(D)); - } - }; + auto PopulateTemplateParameterHashs = [](DeclHashes &Hashes, + const ClassTemplateDecl *TD) { + for (auto *D : TD->getTemplateParameters()->asArray()) { + Hashes.emplace_back(D, computeODRHash(D)); + } + }; PopulateTemplateParameterHashs(FirstTemplateHashes, FirstTemplate); PopulateTemplateParameterHashs(SecondTemplateHashes, SecondTemplate); @@ -10288,11 +10216,11 @@ void ASTReader::diagnoseOdrViolations() { PopulateHashes(FirstHashes, FirstRecord, DC); PopulateHashes(SecondHashes, SecondRecord, DC); - auto DR = FindTypeDiffs(FirstHashes, SecondHashes); + DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes); ODRMismatchDecl FirstDiffType = DR.FirstDiffType; ODRMismatchDecl SecondDiffType = DR.SecondDiffType; - Decl *FirstDecl = DR.FirstDecl; - Decl *SecondDecl = DR.SecondDecl; + const Decl *FirstDecl = DR.FirstDecl; + const Decl *SecondDecl = DR.SecondDecl; if (FirstDiffType == Other || SecondDiffType == Other) { DiagnoseODRUnexpected(DR, FirstRecord, FirstModule, SecondRecord, @@ -10308,8 +10236,56 @@ void ASTReader::diagnoseOdrViolations() { break; } - assert(FirstDiffType == SecondDiffType); + // Used with err_module_odr_violation_record and + // note_module_odr_violation_record + enum ODRCXXRecordDifference { + StaticAssertCondition, + StaticAssertMessage, + StaticAssertOnlyMessage, + MethodName, + MethodDeleted, + MethodDefaulted, + MethodVirtual, + MethodStatic, + MethodVolatile, + MethodConst, + MethodInline, + MethodNumberParameters, + MethodParameterType, + MethodParameterName, + MethodParameterSingleDefaultArgument, + MethodParameterDifferentDefaultArgument, + MethodNoTemplateArguments, + MethodDifferentNumberTemplateArguments, + MethodDifferentTemplateArgument, + MethodSingleBody, + MethodDifferentBody, + FriendTypeFunction, + FriendType, + FriendFunction, + FunctionTemplateDifferentNumberParameters, + FunctionTemplateParameterDifferentKind, + FunctionTemplateParameterName, + FunctionTemplateParameterSingleDefaultArgument, + FunctionTemplateParameterDifferentDefaultArgument, + FunctionTemplateParameterDifferentType, + FunctionTemplatePackParameter, + }; + auto ODRDiagDeclError = [FirstRecord, &FirstModule, + this](SourceLocation Loc, SourceRange Range, + ODRCXXRecordDifference DiffType) { + return Diag(Loc, diag::err_module_odr_violation_record) + << FirstRecord << FirstModule.empty() << FirstModule << Range + << DiffType; + }; + auto ODRDiagDeclNote = [&SecondModule, + this](SourceLocation Loc, SourceRange Range, + ODRCXXRecordDifference DiffType) { + return Diag(Loc, diag::note_module_odr_violation_record) + << SecondModule << Range << DiffType; + }; + assert(FirstDiffType == SecondDiffType); switch (FirstDiffType) { case Other: case EndOfClass: @@ -10319,13 +10295,13 @@ void ASTReader::diagnoseOdrViolations() { llvm_unreachable("Invalid diff type"); case StaticAssert: { - StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl); - StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl); + const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl); + const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl); - Expr *FirstExpr = FirstSA->getAssertExpr(); - Expr *SecondExpr = SecondSA->getAssertExpr(); - unsigned FirstODRHash = ComputeODRHash(FirstExpr); - unsigned SecondODRHash = ComputeODRHash(SecondExpr); + const Expr *FirstExpr = FirstSA->getAssertExpr(); + const Expr *SecondExpr = SecondSA->getAssertExpr(); + unsigned FirstODRHash = computeODRHash(FirstExpr); + unsigned SecondODRHash = computeODRHash(SecondExpr); if (FirstODRHash != SecondODRHash) { ODRDiagDeclError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(), StaticAssertCondition); @@ -10335,8 +10311,8 @@ void ASTReader::diagnoseOdrViolations() { break; } - StringLiteral *FirstStr = FirstSA->getMessage(); - StringLiteral *SecondStr = SecondSA->getMessage(); + const StringLiteral *FirstStr = FirstSA->getMessage(); + const StringLiteral *SecondStr = SecondSA->getMessage(); assert((FirstStr || SecondStr) && "Both messages cannot be empty"); if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) { SourceLocation FirstLoc, SecondLoc; @@ -10451,8 +10427,8 @@ void ASTReader::diagnoseOdrViolations() { // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging, // FirstDecl is the canonical Decl of SecondDecl, so the storage // class needs to be checked instead. - const auto FirstStorage = FirstMethod->getStorageClass(); - const auto SecondStorage = SecondMethod->getStorageClass(); + StorageClass FirstStorage = FirstMethod->getStorageClass(); + StorageClass SecondStorage = SecondMethod->getStorageClass(); const bool FirstStatic = FirstStorage == SC_Static; const bool SecondStatic = SecondStorage == SC_Static; if (FirstStatic != SecondStatic) { @@ -10507,8 +10483,8 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstParamType = FirstParam->getType(); QualType SecondParamType = SecondParam->getType(); if (FirstParamType != SecondParamType && - ComputeQualTypeODRHash(FirstParamType) != - ComputeQualTypeODRHash(SecondParamType)) { + computeODRHash(FirstParamType) != + computeODRHash(SecondParamType)) { if (const DecayedType *ParamDecayedType = FirstParamType->getAs<DecayedType>()) { DiagMethodError(MethodParameterType) @@ -10555,14 +10531,13 @@ void ASTReader::diagnoseOdrViolations() { } if (FirstInit && SecondInit && - ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + computeODRHash(FirstInit) != computeODRHash(SecondInit)) { DiagMethodError(MethodParameterDifferentDefaultArgument) << (I + 1) << FirstInit->getSourceRange(); DiagMethodNote(MethodParameterDifferentDefaultArgument) << (I + 1) << SecondInit->getSourceRange(); ParameterMismatch = true; break; - } } @@ -10571,9 +10546,9 @@ void ASTReader::diagnoseOdrViolations() { break; } - const auto *FirstTemplateArgs = + const TemplateArgumentList *FirstTemplateArgs = FirstMethod->getTemplateSpecializationArgs(); - const auto *SecondTemplateArgs = + const TemplateArgumentList *SecondTemplateArgs = SecondMethod->getTemplateSpecializationArgs(); if ((FirstTemplateArgs && !SecondTemplateArgs) || @@ -10619,8 +10594,7 @@ void ASTReader::diagnoseOdrViolations() { for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) { const TemplateArgument &FirstTA = *FirstExpandedList[i], &SecondTA = *SecondExpandedList[i]; - if (ComputeTemplateArgumentODRHash(FirstTA) == - ComputeTemplateArgumentODRHash(SecondTA)) { + if (computeODRHash(FirstTA) == computeODRHash(SecondTA)) { continue; } @@ -10639,10 +10613,10 @@ void ASTReader::diagnoseOdrViolations() { } // Compute the hash of the method as if it has no body. - auto ComputeCXXMethodODRHash = [&Hash](const CXXMethodDecl *D) { - Hash.clear(); - Hash.AddFunctionDecl(D, true /*SkipBody*/); - return Hash.CalculateHash(); + auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) { + ODRHash Hasher; + Hasher.AddFunctionDecl(D, true /*SkipBody*/); + return Hasher.CalculateHash(); }; // Compare the hash generated to the hash stored. A difference means @@ -10684,11 +10658,11 @@ void ASTReader::diagnoseOdrViolations() { break; } case Friend: { - FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); - FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); + const FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); + const FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); - NamedDecl *FirstND = FirstFriend->getFriendDecl(); - NamedDecl *SecondND = SecondFriend->getFriendDecl(); + const NamedDecl *FirstND = FirstFriend->getFriendDecl(); + const NamedDecl *SecondND = SecondFriend->getFriendDecl(); TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); @@ -10707,8 +10681,8 @@ void ASTReader::diagnoseOdrViolations() { if (FirstTSI && SecondTSI) { QualType FirstFriendType = FirstTSI->getType(); QualType SecondFriendType = SecondTSI->getType(); - assert(ComputeQualTypeODRHash(FirstFriendType) != - ComputeQualTypeODRHash(SecondFriendType)); + assert(computeODRHash(FirstFriendType) != + computeODRHash(SecondFriendType)); ODRDiagDeclError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), FriendType) << FirstFriendType; @@ -10729,9 +10703,9 @@ void ASTReader::diagnoseOdrViolations() { break; } case FunctionTemplate: { - FunctionTemplateDecl *FirstTemplate = + const FunctionTemplateDecl *FirstTemplate = cast<FunctionTemplateDecl>(FirstDecl); - FunctionTemplateDecl *SecondTemplate = + const FunctionTemplateDecl *SecondTemplate = cast<FunctionTemplateDecl>(SecondDecl); TemplateParameterList *FirstTPL = @@ -10826,8 +10800,7 @@ void ASTReader::diagnoseOdrViolations() { if (HasFirstDefaultArgument && HasSecondDefaultArgument) { QualType FirstType = FirstTTPD->getDefaultArgument(); QualType SecondType = SecondTTPD->getDefaultArgument(); - if (ComputeQualTypeODRHash(FirstType) != - ComputeQualTypeODRHash(SecondType)) { + if (computeODRHash(FirstType) != computeODRHash(SecondType)) { DiagTemplateError( FunctionTemplateParameterDifferentDefaultArgument) << (i + 1) << FirstType; @@ -10862,6 +10835,14 @@ void ASTReader::diagnoseOdrViolations() { TemplateParameterList *SecondTPL = SecondTTPD->getTemplateParameters(); + auto ComputeTemplateParameterListODRHash = + [](const TemplateParameterList *TPL) { + assert(TPL); + ODRHash Hasher; + Hasher.AddTemplateParameterList(TPL); + return Hasher.CalculateHash(); + }; + if (ComputeTemplateParameterListODRHash(FirstTPL) != ComputeTemplateParameterListODRHash(SecondTPL)) { DiagTemplateError(FunctionTemplateParameterDifferentType) @@ -10892,8 +10873,7 @@ void ASTReader::diagnoseOdrViolations() { FirstTTPD->getDefaultArgument().getArgument(); TemplateArgument SecondTA = SecondTTPD->getDefaultArgument().getArgument(); - if (ComputeTemplateArgumentODRHash(FirstTA) != - ComputeTemplateArgumentODRHash(SecondTA)) { + if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) { DiagTemplateError( FunctionTemplateParameterDifferentDefaultArgument) << (i + 1) << FirstTA; @@ -10925,8 +10905,7 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstType = FirstNTTPD->getType(); QualType SecondType = SecondNTTPD->getType(); - if (ComputeQualTypeODRHash(FirstType) != - ComputeQualTypeODRHash(SecondType)) { + if (computeODRHash(FirstType) != computeODRHash(SecondType)) { DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1); DiagTemplateNote(FunctionTemplateParameterDifferentType) @@ -10953,8 +10932,8 @@ void ASTReader::diagnoseOdrViolations() { if (HasFirstDefaultArgument && HasSecondDefaultArgument) { Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument(); Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument(); - if (ComputeODRHash(FirstDefaultArgument) != - ComputeODRHash(SecondDefaultArgument)) { + if (computeODRHash(FirstDefaultArgument) != + computeODRHash(SecondDefaultArgument)) { DiagTemplateError( FunctionTemplateParameterDifferentDefaultArgument) << (i + 1) << FirstDefaultArgument; @@ -11050,8 +11029,8 @@ void ASTReader::diagnoseOdrViolations() { << SecondModule << Range << DiffType; }; - if (ComputeQualTypeODRHash(FirstFunction->getReturnType()) != - ComputeQualTypeODRHash(SecondFunction->getReturnType())) { + if (computeODRHash(FirstFunction->getReturnType()) != + computeODRHash(SecondFunction->getReturnType())) { ODRDiagError(FirstFunction->getReturnTypeSourceRange().getBegin(), FirstFunction->getReturnTypeSourceRange(), ReturnType) << FirstFunction->getReturnType(); @@ -11065,11 +11044,11 @@ void ASTReader::diagnoseOdrViolations() { assert(FirstFunction->param_size() == SecondFunction->param_size() && "Merged functions with different number of parameters"); - auto ParamSize = FirstFunction->param_size(); + size_t ParamSize = FirstFunction->param_size(); bool ParameterMismatch = false; for (unsigned I = 0; I < ParamSize; ++I) { - auto *FirstParam = FirstFunction->getParamDecl(I); - auto *SecondParam = SecondFunction->getParamDecl(I); + const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(I); + const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(I); assert(getContext().hasSameType(FirstParam->getType(), SecondParam->getType()) && @@ -11089,8 +11068,7 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstParamType = FirstParam->getType(); QualType SecondParamType = SecondParam->getType(); if (FirstParamType != SecondParamType && - ComputeQualTypeODRHash(FirstParamType) != - ComputeQualTypeODRHash(SecondParamType)) { + computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) { if (const DecayedType *ParamDecayedType = FirstParamType->getAs<DecayedType>()) { ODRDiagError(FirstParam->getLocation(), @@ -11134,7 +11112,7 @@ void ASTReader::diagnoseOdrViolations() { } if (FirstInit && SecondInit && - ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { + computeODRHash(FirstInit) != computeODRHash(SecondInit)) { ODRDiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), ParameterDifferentDefaultArgument) << (I + 1) << FirstInit->getSourceRange(); @@ -11145,8 +11123,7 @@ void ASTReader::diagnoseOdrViolations() { break; } - assert(ComputeSubDeclODRHash(FirstParam) == - ComputeSubDeclODRHash(SecondParam) && + assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) && "Undiagnosed parameter difference."); } @@ -11191,16 +11168,14 @@ void ASTReader::diagnoseOdrViolations() { using DeclHashes = llvm::SmallVector<std::pair<EnumConstantDecl *, unsigned>, 4>; - auto PopulateHashes = [&ComputeSubDeclODRHash, FirstEnum]( - DeclHashes &Hashes, EnumDecl *Enum) { + auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, EnumDecl *Enum) { for (auto *D : Enum->decls()) { // Due to decl merging, the first EnumDecl is the parent of // Decls in both records. if (!ODRHash::isDeclToBeProcessed(D, FirstEnum)) continue; assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind"); - Hashes.emplace_back(cast<EnumConstantDecl>(D), - ComputeSubDeclODRHash(D)); + Hashes.emplace_back(cast<EnumConstantDecl>(D), computeODRHash(D)); } }; DeclHashes FirstHashes; @@ -11266,8 +11241,8 @@ void ASTReader::diagnoseOdrViolations() { } if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) { - if (ComputeQualTypeODRHash(FirstUnderlyingType) != - ComputeQualTypeODRHash(SecondUnderlyingType)) { + if (computeODRHash(FirstUnderlyingType) != + computeODRHash(SecondUnderlyingType)) { ODRDiagError(FirstEnum, DifferentSpecifiedTypes) << FirstUnderlyingType; ODRDiagNote(SecondEnum, DifferentSpecifiedTypes) @@ -11292,39 +11267,38 @@ void ASTReader::diagnoseOdrViolations() { for (unsigned I = 0; I < FirstHashes.size(); ++I) { if (FirstHashes[I].second == SecondHashes[I].second) continue; - const EnumConstantDecl *FirstEnumConstant = FirstHashes[I].first; - const EnumConstantDecl *SecondEnumConstant = SecondHashes[I].first; + const EnumConstantDecl *FirstConstant = FirstHashes[I].first; + const EnumConstantDecl *SecondConstant = SecondHashes[I].first; - if (FirstEnumConstant->getDeclName() != - SecondEnumConstant->getDeclName()) { + if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) { - ODRDiagError(FirstEnumConstant, EnumConstantName) - << I + 1 << FirstEnumConstant; - ODRDiagNote(SecondEnumConstant, EnumConstantName) - << I + 1 << SecondEnumConstant; + ODRDiagError(FirstConstant, EnumConstantName) + << I + 1 << FirstConstant; + ODRDiagNote(SecondConstant, EnumConstantName) + << I + 1 << SecondConstant; Diagnosed = true; break; } - const Expr *FirstInit = FirstEnumConstant->getInitExpr(); - const Expr *SecondInit = SecondEnumConstant->getInitExpr(); + const Expr *FirstInit = FirstConstant->getInitExpr(); + const Expr *SecondInit = SecondConstant->getInitExpr(); if (!FirstInit && !SecondInit) continue; if (!FirstInit || !SecondInit) { - ODRDiagError(FirstEnumConstant, EnumConstantSingleInitializer) - << I + 1 << FirstEnumConstant << (FirstInit != nullptr); - ODRDiagNote(SecondEnumConstant, EnumConstantSingleInitializer) - << I + 1 << SecondEnumConstant << (SecondInit != nullptr); + ODRDiagError(FirstConstant, EnumConstantSingleInitializer) + << I + 1 << FirstConstant << (FirstInit != nullptr); + ODRDiagNote(SecondConstant, EnumConstantSingleInitializer) + << I + 1 << SecondConstant << (SecondInit != nullptr); Diagnosed = true; break; } - if (ComputeODRHash(FirstInit) != ComputeODRHash(SecondInit)) { - ODRDiagError(FirstEnumConstant, EnumConstantDifferentInitializer) - << I + 1 << FirstEnumConstant; - ODRDiagNote(SecondEnumConstant, EnumConstantDifferentInitializer) - << I + 1 << SecondEnumConstant; + if (computeODRHash(FirstInit) != computeODRHash(SecondInit)) { + ODRDiagError(FirstConstant, EnumConstantDifferentInitializer) + << I + 1 << FirstConstant; + ODRDiagNote(SecondConstant, EnumConstantDifferentInitializer) + << I + 1 << SecondConstant; Diagnosed = true; break; } diff --git a/contrib/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp index b4506da2bb2b..d70e824224df 100644 --- a/contrib/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm-project/clang/lib/Serialization/ASTReaderDecl.cpp @@ -953,6 +953,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { case FunctionDecl::TK_NonTemplate: mergeRedeclarable(FD, Redecl); break; + case FunctionDecl::TK_DependentNonTemplate: + mergeRedeclarable(FD, Redecl); + FD->setInstantiatedFromDecl(readDeclAs<FunctionDecl>()); + break; case FunctionDecl::TK_FunctionTemplate: // Merged when we merge the template. FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>()); diff --git a/contrib/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp index 01f692c9611b..35b8db27bd0e 100644 --- a/contrib/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm-project/clang/lib/Serialization/ASTWriterDecl.cpp @@ -585,6 +585,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { switch (D->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: break; + case FunctionDecl::TK_DependentNonTemplate: + Record.AddDeclRef(D->getInstantiatedFromDecl()); + break; case FunctionDecl::TK_FunctionTemplate: Record.AddDeclRef(D->getDescribedFunctionTemplate()); break; diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 1c33648b2b32..ec1b0a70d7d3 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -40,6 +40,7 @@ class ExprInspectionChecker void analyzerNumTimesReached(const CallExpr *CE, CheckerContext &C) const; void analyzerCrash(const CallExpr *CE, CheckerContext &C) const; void analyzerWarnOnDeadSymbol(const CallExpr *CE, CheckerContext &C) const; + void analyzerValue(const CallExpr *CE, CheckerContext &C) const; void analyzerDumpSValType(const CallExpr *CE, CheckerContext &C) const; void analyzerDump(const CallExpr *CE, CheckerContext &C) const; void analyzerExplain(const CallExpr *CE, CheckerContext &C) const; @@ -60,6 +61,7 @@ class ExprInspectionChecker Optional<SVal> ExprVal = None) const; ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, ExplodedNode *N, Optional<SVal> ExprVal = None) const; + template <typename T> void printAndReport(CheckerContext &C, T What) const; const Expr *getArgExpr(const CallExpr *CE, CheckerContext &C) const; const MemRegion *getArgRegion(const CallExpr *CE, CheckerContext &C) const; @@ -99,6 +101,7 @@ bool ExprInspectionChecker::evalCall(const CallEvent &Call, &ExprInspectionChecker::analyzerDumpExtent) .Case("clang_analyzer_dumpElementCount", &ExprInspectionChecker::analyzerDumpElementCount) + .Case("clang_analyzer_value", &ExprInspectionChecker::analyzerValue) .StartsWith("clang_analyzer_dumpSvalType", &ExprInspectionChecker::analyzerDumpSValType) .StartsWith("clang_analyzer_dump", @@ -258,6 +261,45 @@ void ExprInspectionChecker::analyzerExplain(const CallExpr *CE, reportBug(Ex.Visit(V), C); } +static void printHelper(llvm::raw_svector_ostream &Out, CheckerContext &C, + const llvm::APSInt &I) { + Out << I.getBitWidth() << (I.isUnsigned() ? "u:" : "s:"); + Out << I; +} + +static void printHelper(llvm::raw_svector_ostream &Out, CheckerContext &C, + SymbolRef Sym) { + C.getConstraintManager().printValue(Out, C.getState(), Sym); +} + +static void printHelper(llvm::raw_svector_ostream &Out, CheckerContext &C, + SVal V) { + Out << V; +} + +template <typename T> +void ExprInspectionChecker::printAndReport(CheckerContext &C, T What) const { + llvm::SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + printHelper(OS, C, What); + reportBug(OS.str(), C); +} + +void ExprInspectionChecker::analyzerValue(const CallExpr *CE, + CheckerContext &C) const { + const Expr *Arg = getArgExpr(CE, C); + if (!Arg) + return; + + SVal V = C.getSVal(Arg); + if (const SymbolRef Sym = V.getAsSymbol()) + printAndReport(C, Sym); + else if (const llvm::APSInt *I = V.getAsInteger()) + printAndReport(C, *I); + else + reportBug("n/a", C); +} + void ExprInspectionChecker::analyzerDumpSValType(const CallExpr *CE, CheckerContext &C) const { const Expr *Arg = getArgExpr(CE, C); @@ -275,11 +317,7 @@ void ExprInspectionChecker::analyzerDump(const CallExpr *CE, return; SVal V = C.getSVal(Arg); - - llvm::SmallString<32> Str; - llvm::raw_svector_ostream OS(Str); - V.dumpToStream(OS); - reportBug(OS.str(), C); + printAndReport(C, V); } void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE, @@ -303,11 +341,7 @@ void ExprInspectionChecker::analyzerDumpExtent(const CallExpr *CE, DefinedOrUnknownSVal Size = getDynamicExtent(C.getState(), MR, C.getSValBuilder()); - - SmallString<64> Msg; - llvm::raw_svector_ostream Out(Msg); - Out << Size; - reportBug(Out.str(), C); + printAndReport(C, Size); } void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE, @@ -328,11 +362,7 @@ void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE, DefinedOrUnknownSVal ElementCount = getDynamicElementCount(C.getState(), MR, C.getSValBuilder(), ElementTy); - - SmallString<128> Msg; - llvm::raw_svector_ostream Out(Msg); - Out << ElementCount; - reportBug(Out.str(), C); + printAndReport(C, ElementCount); } void ExprInspectionChecker::analyzerPrintState(const CallExpr *CE, diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 45af22de50ae..d8f56f2f8cff 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -185,6 +185,17 @@ typedef llvm::ImmutableMap<ConstructedObjectKey, SVal> REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction, ObjectsUnderConstructionMap) +// This trait is responsible for storing the index of the element that is to be +// constructed in the next iteration. As a result a CXXConstructExpr is only +// stored if it is array type. Also the index is the index of the continous +// memory region, which is important for multi-dimensional arrays. E.g:: int +// arr[2][2]; assume arr[1][1] will be the next element under construction, so +// the index is 3. +typedef llvm::ImmutableMap< + std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned> + IndexOfElementToConstructMap; +REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct, + IndexOfElementToConstructMap) //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -441,16 +452,65 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( return State; } +ProgramStateRef ExprEngine::setIndexOfElementToConstruct( + ProgramStateRef State, const CXXConstructExpr *E, + const LocationContext *LCtx, unsigned Idx) { + auto Key = std::make_pair(E, LCtx->getStackFrame()); + + assert(!State->contains<IndexOfElementToConstruct>(Key) || Idx > 0); + + return State->set<IndexOfElementToConstruct>(Key, Idx); +} + +Optional<unsigned> +ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx) { + + return Optional<unsigned>::create( + State->get<IndexOfElementToConstruct>({E, LCtx->getStackFrame()})); +} + +ProgramStateRef +ExprEngine::removeIndexOfElementToConstruct(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx) { + auto Key = std::make_pair(E, LCtx->getStackFrame()); + + assert(E && State->contains<IndexOfElementToConstruct>(Key)); + return State->remove<IndexOfElementToConstruct>(Key); +} + ProgramStateRef ExprEngine::addObjectUnderConstruction(ProgramStateRef State, const ConstructionContextItem &Item, const LocationContext *LC, SVal V) { ConstructedObjectKey Key(Item, LC->getStackFrame()); + + const CXXConstructExpr *E = nullptr; + + if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) { + if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) + E = dyn_cast<CXXConstructExpr>(VD->getInit()); + } + + if (!E && !Item.getStmtOrNull()) { + auto CtorInit = Item.getCXXCtorInitializer(); + E = dyn_cast<CXXConstructExpr>(CtorInit->getInit()); + } + // FIXME: Currently the state might already contain the marker due to // incorrect handling of temporaries bound to default parameters. - assert(!State->get<ObjectsUnderConstruction>(Key) || - Key.getItem().getKind() == - ConstructionContextItem::TemporaryDestructorKind); + // The state will already contain the marker if we construct elements + // in an array, as we visit the same statement multiple times before + // the array declaration. The marker is removed when we exit the + // constructor call. + assert((!State->get<ObjectsUnderConstruction>(Key) || + Key.getItem().getKind() == + ConstructionContextItem::TemporaryDestructorKind || + State->contains<IndexOfElementToConstruct>({E, LC})) && + "The object is already marked as `UnderConstruction`, when it's not " + "supposed to!"); return State->set<ObjectsUnderConstruction>(Key, V); } @@ -582,6 +642,69 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State, } } +static void printIndicesOfElementsToConstructJson( + raw_ostream &Out, ProgramStateRef State, const char *NL, + const LocationContext *LCtx, const ASTContext &Context, + unsigned int Space = 0, bool IsDot = false) { + using KeyT = std::pair<const Expr *, const LocationContext *>; + + PrintingPolicy PP = + LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + + ++Space; + bool HasItem = false; + + // Store the last key. + KeyT LastKey; + for (const auto &I : State->get<IndexOfElementToConstruct>()) { + const KeyT &Key = I.first; + if (Key.second != LCtx) + continue; + + if (!HasItem) { + Out << "[" << NL; + HasItem = true; + } + + LastKey = Key; + } + + for (const auto &I : State->get<IndexOfElementToConstruct>()) { + const KeyT &Key = I.first; + unsigned Value = I.second; + if (Key.second != LCtx) + continue; + + Indent(Out, Space, IsDot) << "{ "; + + // Expr + const Expr *E = Key.first; + Out << "\"stmt_id\": " << E->getID(Context); + + // Kind - hack to display the current index + Out << ", \"kind\": \"Cur: " << Value - 1 << "\""; + + // Pretty-print + Out << ", \"pretty\": "; + Out << "\"" << E->getStmtClassName() << " " + << E->getSourceRange().printToString(Context.getSourceManager()) << " '" + << QualType::getAsString(E->getType().split(), PP); + Out << "'\""; + + Out << ", \"value\": \"Next: " << Value << "\" }"; + + if (Key != LastKey) + Out << ','; + Out << NL; + } + + if (HasItem) + Indent(Out, --Space, IsDot) << ']'; // End of "location_context". + else { + Out << "null "; + } +} + void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx, const char *NL, unsigned int Space, bool IsDot) const { @@ -600,6 +723,23 @@ void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State, Out << "null," << NL; } + Indent(Out, Space, IsDot) << "\"index_of_element\": "; + if (LCtx && !State->get<IndexOfElementToConstruct>().isEmpty()) { + ++Space; + + auto &Context = getContext(); + Out << '[' << NL; + LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) { + printIndicesOfElementsToConstructJson(Out, State, NL, LC, Context, Space, + IsDot); + }); + + --Space; + Indent(Out, Space, IsDot) << "]," << NL; // End of "index_of_element". + } else { + Out << "null," << NL; + } + getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space, IsDot); } @@ -961,8 +1101,9 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, // This workaround will just run the first destructor (which will still // invalidate the entire array). EvalCallOptions CallOpts; - Region = makeZeroElementRegion(state, loc::MemRegionVal(Region), varType, - CallOpts.IsArrayCtorOrDtor).getAsRegion(); + Region = makeElementRegion(state, loc::MemRegionVal(Region), varType, + CallOpts.IsArrayCtorOrDtor) + .getAsRegion(); VisitCXXDestructor(varType, Region, Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst, CallOpts); @@ -1045,8 +1186,7 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, // This workaround will just run the first destructor (which will still // invalidate the entire array). EvalCallOptions CallOpts; - FieldVal = makeZeroElementRegion(State, FieldVal, T, - CallOpts.IsArrayCtorOrDtor); + FieldVal = makeElementRegion(State, FieldVal, T, CallOpts.IsArrayCtorOrDtor); VisitCXXDestructor(T, FieldVal.getAsRegion(), CurDtor->getBody(), /*IsBase=*/false, Pred, Dst, CallOpts); @@ -1105,7 +1245,7 @@ void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, CallOpts.IsArrayCtorOrDtor = true; } } else { - // We'd eventually need to makeZeroElementRegion() trick here, + // We'd eventually need to makeElementRegion() trick here, // but for now we don't have the respective construction contexts, // so MR would always be null in this case. Do nothing for now. } diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 6d979da2755f..08fac9fb2e69 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -94,15 +94,17 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, } } - -SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue, - QualType &Ty, bool &IsArray) { +SVal ExprEngine::makeElementRegion(ProgramStateRef State, SVal LValue, + QualType &Ty, bool &IsArray, unsigned Idx) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); ASTContext &Ctx = SVB.getContext(); - while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) { - Ty = AT->getElementType(); - LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue); + if (const ArrayType *AT = Ctx.getAsArrayType(Ty)) { + while (AT) { + Ty = AT->getElementType(); + AT = dyn_cast<ArrayType>(AT->getElementType()); + } + LValue = State->getLValue(Ty, SVB.makeArrayIndex(Idx), LValue); IsArray = true; } @@ -111,7 +113,7 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue, SVal ExprEngine::computeObjectUnderConstruction( const Expr *E, ProgramStateRef State, const LocationContext *LCtx, - const ConstructionContext *CC, EvalCallOptions &CallOpts) { + const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx) { SValBuilder &SVB = getSValBuilder(); MemRegionManager &MRMgr = SVB.getRegionManager(); ASTContext &ACtx = SVB.getContext(); @@ -125,8 +127,8 @@ SVal ExprEngine::computeObjectUnderConstruction( const auto *DS = DSCC->getDeclStmt(); const auto *Var = cast<VarDecl>(DS->getSingleDecl()); QualType Ty = Var->getType(); - return makeZeroElementRegion(State, State->getLValue(Var, LCtx), Ty, - CallOpts.IsArrayCtorOrDtor); + return makeElementRegion(State, State->getLValue(Var, LCtx), Ty, + CallOpts.IsArrayCtorOrDtor, Idx); } case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind: case ConstructionContext::SimpleConstructorInitializerKind: { @@ -158,8 +160,8 @@ SVal ExprEngine::computeObjectUnderConstruction( } QualType Ty = Field->getType(); - return makeZeroElementRegion(State, FieldVal, Ty, - CallOpts.IsArrayCtorOrDtor); + return makeElementRegion(State, FieldVal, Ty, CallOpts.IsArrayCtorOrDtor, + Idx); } case ConstructionContext::NewAllocatedObjectKind: { if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) { @@ -172,8 +174,12 @@ SVal ExprEngine::computeObjectUnderConstruction( // TODO: In fact, we need to call the constructor for every // allocated element, not just the first one! CallOpts.IsArrayCtorOrDtor = true; - return loc::MemRegionVal(getStoreManager().GetElementZeroRegion( - MR, NE->getType()->getPointeeType())); + + auto R = MRMgr.getElementRegion(NE->getType()->getPointeeType(), + svalBuilder.makeArrayIndex(Idx), MR, + SVB.getContext()); + + return loc::MemRegionVal(R); } return V; } @@ -484,10 +490,6 @@ void ExprEngine::handleConstructor(const Expr *E, } } - // FIXME: Handle arrays, which run the same constructor for every element. - // For now, we just run the first constructor (which should still invalidate - // the entire array). - EvalCallOptions CallOpts; auto C = getCurrentCFGElement().getAs<CFGConstructor>(); assert(C || getCurrentCFGElement().getAs<CFGStmt>()); @@ -500,9 +502,15 @@ void ExprEngine::handleConstructor(const Expr *E, // Inherited constructors are always base class constructors. assert(CE && !CIE && "A complete constructor is inherited?!"); + unsigned Idx = 0; + if (CE->getType()->isArrayType()) { + Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u); + State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1); + } + // The target region is found from construction context. std::tie(State, Target) = - handleConstructionContext(CE, State, LCtx, CC, CallOpts); + handleConstructionContext(CE, State, LCtx, CC, CallOpts, Idx); break; } case CXXConstructExpr::CK_VirtualBase: { @@ -894,14 +902,39 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, SVal Result = symVal; if (CNE->isArray()) { - // FIXME: allocating an array requires simulating the constructors. - // For now, just return a symbolicated region. + if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) { - QualType ObjTy = CNE->getType()->getPointeeType(); + // If each element is initialized by their default constructor, the field + // values are properly placed inside the required region, however if an + // initializer list is used, this doesn't happen automatically. + auto *Init = CNE->getInitializer(); + bool isInitList = dyn_cast_or_null<InitListExpr>(Init); + + QualType ObjTy = + isInitList ? Init->getType() : CNE->getType()->getPointeeType(); const ElementRegion *EleReg = - getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + MRMgr.getElementRegion(ObjTy, svalBuilder.makeArrayIndex(0), NewReg, + svalBuilder.getContext()); Result = loc::MemRegionVal(EleReg); + + // If the array is list initialized, we bind the initializer list to the + // memory region here, otherwise we would lose it. + if (isInitList) { + Bldr.takeNodes(Pred); + Pred = Bldr.generateNode(CNE, Pred, State); + + SVal V = State->getSVal(Init, LCtx); + ExplodedNodeSet evaluated; + evalBind(evaluated, CNE, Pred, Result, V, true); + + Bldr.takeNodes(Pred); + Bldr.addNodes(evaluated); + + Pred = *evaluated.begin(); + State = Pred->getState(); + } } + State = State->BindExpr(CNE, Pred->getLocationContext(), Result); Bldr.generateNode(CNE, Pred, State); return; diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index e1649f0b3df6..ebcca92a3e4e 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -227,6 +227,13 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // Step 2: generate node with bound return value: CEBNode -> BindedRetNode. + // If this variable is set to 'true' the analyzer will evaluate the call + // statement we are about to exit again, instead of continuing the execution + // from the statement after the call. This is useful for non-POD type array + // construction where the CXXConstructExpr is referenced only once in the CFG, + // but we want to evaluate it as many times as many elements the array has. + bool ShouldRepeatCall = false; + // If the callee returns an expression, bind its value to CallExpr. if (CE) { if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { @@ -255,6 +262,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { SVal ThisV = state->getSVal(This); ThisV = state->getSVal(ThisV.castAs<Loc>()); state = state->BindExpr(CCE, callerCtx, ThisV); + + ShouldRepeatCall = shouldRepeatCtorCall(state, CCE, callerCtx); + + if (!ShouldRepeatCall && + getIndexOfElementToConstruct(state, CCE, callerCtx)) + state = removeIndexOfElementToConstruct(state, CCE, callerCtx); } if (const auto *CNE = dyn_cast<CXXNewExpr>(CE)) { @@ -358,9 +371,10 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // Enqueue the next element in the block. for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end(); - PSI != PSE; ++PSI) { - Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), - calleeCtx->getIndex()+1); + PSI != PSE; ++PSI) { + unsigned Idx = calleeCtx->getIndex() + (ShouldRepeatCall ? 0 : 1); + + Engine.getWorkList()->enqueue(*PSI, calleeCtx->getCallSiteBlock(), Idx); } } } @@ -800,8 +814,11 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, // initializers for array fields in default move/copy constructors. // We still allow construction into ElementRegion targets when they don't // represent array elements. - if (CallOpts.IsArrayCtorOrDtor) - return CIP_DisallowedOnce; + if (CallOpts.IsArrayCtorOrDtor) { + if (!shouldInlineArrayConstruction( + dyn_cast<ArrayType>(CtorExpr->getType()))) + return CIP_DisallowedOnce; + } // Inlining constructors requires including initializers in the CFG. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); @@ -852,7 +869,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); (void)ADC; - // FIXME: We don't handle constructors or destructors for arrays properly. + // FIXME: We don't handle destructors for arrays properly. if (CallOpts.IsArrayCtorOrDtor) return CIP_DisallowedOnce; @@ -1065,6 +1082,38 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, return true; } +bool ExprEngine::shouldInlineArrayConstruction(const ArrayType *Type) { + if (!Type) + return false; + + // FIXME: Handle other arrays types. + if (const auto *CAT = dyn_cast<ConstantArrayType>(Type)) { + unsigned Size = getContext().getConstantArrayElementCount(CAT); + + return Size <= AMgr.options.maxBlockVisitOnPath; + } + + return false; +} + +bool ExprEngine::shouldRepeatCtorCall(ProgramStateRef State, + const CXXConstructExpr *E, + const LocationContext *LCtx) { + + if (!E) + return false; + + auto Ty = E->getType(); + + // FIXME: Handle non constant array types + if (const auto *CAT = dyn_cast<ConstantArrayType>(Ty)) { + unsigned Size = getContext().getConstantArrayElementCount(CAT); + return Size > getIndexOfElementToConstruct(State, E, LCtx); + } + + return false; +} + static bool isTrivialObjectAssignment(const CallEvent &Call) { const CXXInstanceCall *ICall = dyn_cast<CXXInstanceCall>(&Call); if (!ICall) diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index f0cda835e07c..81c11099e93f 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -794,7 +794,11 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, if (Size.isZero()) return true; + if (getContext().getLangOpts().StrictFlexArrays >= 2) + return false; + const AnalyzerOptions &Opts = SVB.getAnalyzerOptions(); + // FIXME: this option is probably redundant with -fstrict-flex-arrays=1. if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers && Size.isOne()) return true; diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index e788a7a60830..2d4dfae1e750 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -1213,13 +1213,21 @@ public: } RangeSet VisitSymExpr(SymbolRef Sym) { - // If we got to this function, the actual type of the symbolic + if (Optional<RangeSet> RS = getRangeForNegatedSym(Sym)) + return *RS; + // If we've reached this line, the actual type of the symbolic // expression is not supported for advanced inference. // In this case, we simply backoff to the default "let's simply // infer the range from the expression's type". return infer(Sym->getType()); } + RangeSet VisitUnarySymExpr(const UnarySymExpr *USE) { + if (Optional<RangeSet> RS = getRangeForNegatedUnarySym(USE)) + return *RS; + return infer(USE->getType()); + } + RangeSet VisitSymIntExpr(const SymIntExpr *Sym) { return VisitBinaryOperator(Sym); } @@ -1228,14 +1236,25 @@ public: return VisitBinaryOperator(Sym); } - RangeSet VisitSymSymExpr(const SymSymExpr *Sym) { + RangeSet VisitSymSymExpr(const SymSymExpr *SSE) { return intersect( RangeFactory, + // If Sym is a difference of symbols A - B, then maybe we have range + // set stored for B - A. + // + // If we have range set stored for both A - B and B - A then + // calculate the effective range set by intersecting the range set + // for A - B and the negated range set of B - A. + getRangeForNegatedSymSym(SSE), + // If Sym is a comparison expression (except <=>), + // find any other comparisons with the same operands. + // See function description. + getRangeForComparisonSymbol(SSE), // If Sym is (dis)equality, we might have some information // on that in our equality classes data structure. - getRangeForEqualities(Sym), + getRangeForEqualities(SSE), // And we should always check what we can get from the operands. - VisitBinaryOperator(Sym)); + VisitBinaryOperator(SSE)); } private: @@ -1264,25 +1283,13 @@ private: } RangeSet infer(SymbolRef Sym) { - return intersect( - RangeFactory, - // Of course, we should take the constraint directly associated with - // this symbol into consideration. - getConstraint(State, Sym), - // If Sym is a difference of symbols A - B, then maybe we have range - // set stored for B - A. - // - // If we have range set stored for both A - B and B - A then - // calculate the effective range set by intersecting the range set - // for A - B and the negated range set of B - A. - getRangeForNegatedSub(Sym), - // If Sym is a comparison expression (except <=>), - // find any other comparisons with the same operands. - // See function description. - getRangeForComparisonSymbol(Sym), - // Apart from the Sym itself, we can infer quite a lot if we look - // into subexpressions of Sym. - Visit(Sym)); + return intersect(RangeFactory, + // Of course, we should take the constraint directly + // associated with this symbol into consideration. + getConstraint(State, Sym), + // Apart from the Sym itself, we can infer quite a lot if + // we look into subexpressions of Sym. + Visit(Sym)); } RangeSet infer(EquivalenceClass Class) { @@ -1443,38 +1450,53 @@ private: return RangeFactory.deletePoint(Domain, IntType.getZeroValue()); } - Optional<RangeSet> getRangeForNegatedSub(SymbolRef Sym) { + template <typename ProduceNegatedSymFunc> + Optional<RangeSet> getRangeForNegatedExpr(ProduceNegatedSymFunc F, + QualType T) { // Do not negate if the type cannot be meaningfully negated. - if (!Sym->getType()->isUnsignedIntegerOrEnumerationType() && - !Sym->getType()->isSignedIntegerOrEnumerationType()) + if (!T->isUnsignedIntegerOrEnumerationType() && + !T->isSignedIntegerOrEnumerationType()) return llvm::None; - const RangeSet *NegatedRange = nullptr; - SymbolManager &SymMgr = State->getSymbolManager(); - if (const auto *USE = dyn_cast<UnarySymExpr>(Sym)) { - if (USE->getOpcode() == UO_Minus) { - // Just get the operand when we negate a symbol that is already negated. - // -(-a) == a - NegatedRange = getConstraint(State, USE->getOperand()); - } - } else if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(Sym)) { - if (SSE->getOpcode() == BO_Sub) { - QualType T = Sym->getType(); - SymbolRef NegatedSym = - SymMgr.getSymSymExpr(SSE->getRHS(), BO_Sub, SSE->getLHS(), T); - NegatedRange = getConstraint(State, NegatedSym); - } - } else { - SymbolRef NegatedSym = - SymMgr.getUnarySymExpr(Sym, UO_Minus, Sym->getType()); - NegatedRange = getConstraint(State, NegatedSym); - } + if (SymbolRef NegatedSym = F()) + if (const RangeSet *NegatedRange = getConstraint(State, NegatedSym)) + return RangeFactory.negate(*NegatedRange); - if (NegatedRange) - return RangeFactory.negate(*NegatedRange); return llvm::None; } + Optional<RangeSet> getRangeForNegatedUnarySym(const UnarySymExpr *USE) { + // Just get the operand when we negate a symbol that is already negated. + // -(-a) == a + return getRangeForNegatedExpr( + [USE]() -> SymbolRef { + if (USE->getOpcode() == UO_Minus) + return USE->getOperand(); + return nullptr; + }, + USE->getType()); + } + + Optional<RangeSet> getRangeForNegatedSymSym(const SymSymExpr *SSE) { + return getRangeForNegatedExpr( + [SSE, State = this->State]() -> SymbolRef { + if (SSE->getOpcode() == BO_Sub) + return State->getSymbolManager().getSymSymExpr( + SSE->getRHS(), BO_Sub, SSE->getLHS(), SSE->getType()); + return nullptr; + }, + SSE->getType()); + } + + Optional<RangeSet> getRangeForNegatedSym(SymbolRef Sym) { + return getRangeForNegatedExpr( + [Sym, State = this->State]() { + return State->getSymbolManager().getUnarySymExpr(Sym, UO_Minus, + Sym->getType()); + }, + Sym->getType()); + } + // Returns ranges only for binary comparison operators (except <=>) // when left and right operands are symbolic values. // Finds any other comparisons with the same operands. @@ -1485,11 +1507,7 @@ private: // It covers all possible combinations (see CmpOpTable description). // Note that `x` and `y` can also stand for subexpressions, // not only for actual symbols. - Optional<RangeSet> getRangeForComparisonSymbol(SymbolRef Sym) { - const auto *SSE = dyn_cast<SymSymExpr>(Sym); - if (!SSE) - return llvm::None; - + Optional<RangeSet> getRangeForComparisonSymbol(const SymSymExpr *SSE) { const BinaryOperatorKind CurrentOP = SSE->getOpcode(); // We currently do not support <=> (C++20). @@ -1801,6 +1819,8 @@ public: void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", unsigned int Space = 0, bool IsDot = false) const override; + void printValue(raw_ostream &Out, ProgramStateRef State, + SymbolRef Sym) override; void printConstraints(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", unsigned int Space = 0, bool IsDot = false) const; @@ -3154,6 +3174,13 @@ void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State, printDisequalities(Out, State, NL, Space, IsDot); } +void RangeConstraintManager::printValue(raw_ostream &Out, ProgramStateRef State, + SymbolRef Sym) { + const RangeSet RS = getRange(State, Sym); + Out << RS.getBitWidth() << (RS.isUnsigned() ? "u:" : "s:"); + RS.dump(Out); +} + static std::string toString(const SymbolRef &Sym) { std::string S; llvm::raw_string_ostream O(S); diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index cf3d13ffb7ba..d90e869196eb 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -19,15 +19,16 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/Stmt.h" #include "clang/AST/Type.h" -#include "clang/Basic/LLVM.h" #include "clang/Analysis/AnalysisDeclContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/Basic/LLVM.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" @@ -617,517 +618,478 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val, } //===----------------------------------------------------------------------===// -// Cast methods. -// `evalCast` is the main method -// `evalCastKind` and `evalCastSubKind` are helpers +// Cast method. +// `evalCast` and its helper `EvalCastVisitor` //===----------------------------------------------------------------------===// -/// Cast a given SVal to another SVal using given QualType's. -/// \param V -- SVal that should be casted. -/// \param CastTy -- QualType that V should be casted according to. -/// \param OriginalTy -- QualType which is associated to V. It provides -/// additional information about what type the cast performs from. -/// \returns the most appropriate casted SVal. -/// Note: Many cases don't use an exact OriginalTy. It can be extracted -/// from SVal or the cast can performs unconditionaly. Always pass OriginalTy! -/// It can be crucial in certain cases and generates different results. -/// FIXME: If `OriginalTy.isNull()` is true, then cast performs based on CastTy -/// only. This behavior is uncertain and should be improved. -SVal SValBuilder::evalCast(SVal V, QualType CastTy, QualType OriginalTy) { - if (CastTy.isNull()) - return V; - - CastTy = Context.getCanonicalType(CastTy); +namespace { +class EvalCastVisitor : public SValVisitor<EvalCastVisitor, SVal> { +private: + SValBuilder &VB; + ASTContext &Context; + QualType CastTy, OriginalTy; - const bool IsUnknownOriginalType = OriginalTy.isNull(); - if (!IsUnknownOriginalType) { - OriginalTy = Context.getCanonicalType(OriginalTy); +public: + EvalCastVisitor(SValBuilder &VB, QualType CastTy, QualType OriginalTy) + : VB(VB), Context(VB.getContext()), CastTy(CastTy), + OriginalTy(OriginalTy) {} - if (CastTy == OriginalTy) + SVal Visit(SVal V) { + if (CastTy.isNull()) return V; - // FIXME: Move this check to the most appropriate - // evalCastKind/evalCastSubKind function. For const casts, casts to void, - // just propagate the value. - if (!CastTy->isVariableArrayType() && !OriginalTy->isVariableArrayType()) - if (shouldBeModeledWithNoOp(Context, Context.getPointerType(CastTy), - Context.getPointerType(OriginalTy))) - return V; - } - - // Cast SVal according to kinds. - switch (V.getBaseKind()) { - case SVal::UndefinedValKind: - return evalCastKind(V.castAs<UndefinedVal>(), CastTy, OriginalTy); - case SVal::UnknownValKind: - return evalCastKind(V.castAs<UnknownVal>(), CastTy, OriginalTy); - case SVal::LocKind: - return evalCastKind(V.castAs<Loc>(), CastTy, OriginalTy); - case SVal::NonLocKind: - return evalCastKind(V.castAs<NonLoc>(), CastTy, OriginalTy); - } - - llvm_unreachable("Unknown SVal kind"); -} - -SVal SValBuilder::evalCastKind(UndefinedVal V, QualType CastTy, - QualType OriginalTy) { - return V; -} - -SVal SValBuilder::evalCastKind(UnknownVal V, QualType CastTy, - QualType OriginalTy) { - return V; -} - -SVal SValBuilder::evalCastKind(Loc V, QualType CastTy, QualType OriginalTy) { - switch (V.getSubKind()) { - case loc::ConcreteIntKind: - return evalCastSubKind(V.castAs<loc::ConcreteInt>(), CastTy, OriginalTy); - case loc::GotoLabelKind: - return evalCastSubKind(V.castAs<loc::GotoLabel>(), CastTy, OriginalTy); - case loc::MemRegionValKind: - return evalCastSubKind(V.castAs<loc::MemRegionVal>(), CastTy, OriginalTy); - } - - llvm_unreachable("Unknown SVal kind"); -} - -SVal SValBuilder::evalCastKind(NonLoc V, QualType CastTy, QualType OriginalTy) { - switch (V.getSubKind()) { - case nonloc::CompoundValKind: - return evalCastSubKind(V.castAs<nonloc::CompoundVal>(), CastTy, OriginalTy); - case nonloc::ConcreteIntKind: - return evalCastSubKind(V.castAs<nonloc::ConcreteInt>(), CastTy, OriginalTy); - case nonloc::LazyCompoundValKind: - return evalCastSubKind(V.castAs<nonloc::LazyCompoundVal>(), CastTy, - OriginalTy); - case nonloc::LocAsIntegerKind: - return evalCastSubKind(V.castAs<nonloc::LocAsInteger>(), CastTy, - OriginalTy); - case nonloc::SymbolValKind: - return evalCastSubKind(V.castAs<nonloc::SymbolVal>(), CastTy, OriginalTy); - case nonloc::PointerToMemberKind: - return evalCastSubKind(V.castAs<nonloc::PointerToMember>(), CastTy, - OriginalTy); - } + CastTy = Context.getCanonicalType(CastTy); - llvm_unreachable("Unknown SVal kind"); -} + const bool IsUnknownOriginalType = OriginalTy.isNull(); + if (!IsUnknownOriginalType) { + OriginalTy = Context.getCanonicalType(OriginalTy); -SVal SValBuilder::evalCastSubKind(loc::ConcreteInt V, QualType CastTy, - QualType OriginalTy) { - // Pointer to bool. - if (CastTy->isBooleanType()) - return makeTruthVal(V.getValue().getBoolValue(), CastTy); - - // Pointer to integer. - if (CastTy->isIntegralOrEnumerationType()) { - llvm::APSInt Value = V.getValue(); - BasicVals.getAPSIntType(CastTy).apply(Value); - return makeIntVal(Value); - } + if (CastTy == OriginalTy) + return V; - // Pointer to any pointer. - if (Loc::isLocType(CastTy)) { - llvm::APSInt Value = V.getValue(); - BasicVals.getAPSIntType(CastTy).apply(Value); - return loc::ConcreteInt(BasicVals.getValue(Value)); + // FIXME: Move this check to the most appropriate + // evalCastKind/evalCastSubKind function. For const casts, casts to void, + // just propagate the value. + if (!CastTy->isVariableArrayType() && !OriginalTy->isVariableArrayType()) + if (shouldBeModeledWithNoOp(Context, Context.getPointerType(CastTy), + Context.getPointerType(OriginalTy))) + return V; + } + return SValVisitor::Visit(V); } + SVal VisitUndefinedVal(UndefinedVal V) { return V; } + SVal VisitUnknownVal(UnknownVal V) { return V; } + SVal VisitLocConcreteInt(loc::ConcreteInt V) { + // Pointer to bool. + if (CastTy->isBooleanType()) + return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy); + + // Pointer to integer. + if (CastTy->isIntegralOrEnumerationType()) { + llvm::APSInt Value = V.getValue(); + VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value); + return VB.makeIntVal(Value); + } - // Pointer to whatever else. - return UnknownVal(); -} - -SVal SValBuilder::evalCastSubKind(loc::GotoLabel V, QualType CastTy, - QualType OriginalTy) { - // Pointer to bool. - if (CastTy->isBooleanType()) - // Labels are always true. - return makeTruthVal(true, CastTy); - - // Pointer to integer. - if (CastTy->isIntegralOrEnumerationType()) { - const unsigned BitWidth = Context.getIntWidth(CastTy); - return makeLocAsInteger(V, BitWidth); - } + // Pointer to any pointer. + if (Loc::isLocType(CastTy)) { + llvm::APSInt Value = V.getValue(); + VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value); + return loc::ConcreteInt(VB.getBasicValueFactory().getValue(Value)); + } - const bool IsUnknownOriginalType = OriginalTy.isNull(); - if (!IsUnknownOriginalType) { - // Array to pointer. - if (isa<ArrayType>(OriginalTy)) - if (CastTy->isPointerType() || CastTy->isReferenceType()) - return UnknownVal(); + // Pointer to whatever else. + return UnknownVal(); } - - // Pointer to any pointer. - if (Loc::isLocType(CastTy)) - return V; - - // Pointer to whatever else. - return UnknownVal(); -} - -static bool hasSameUnqualifiedPointeeType(QualType ty1, QualType ty2) { - return ty1->getPointeeType().getCanonicalType().getTypePtr() == - ty2->getPointeeType().getCanonicalType().getTypePtr(); -} - -SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, QualType CastTy, - QualType OriginalTy) { - // Pointer to bool. - if (CastTy->isBooleanType()) { - const MemRegion *R = V.getRegion(); - if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R)) - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl())) - if (FD->isWeak()) - // FIXME: Currently we are using an extent symbol here, - // because there are no generic region address metadata - // symbols to use, only content metadata. - return nonloc::SymbolVal(SymMgr.getExtentSymbol(FTR)); - - if (const SymbolicRegion *SymR = R->getSymbolicBase()) { - SymbolRef Sym = SymR->getSymbol(); - QualType Ty = Sym->getType(); - // This change is needed for architectures with varying - // pointer widths. See the amdgcn opencl reproducer with - // this change as an example: solver-sym-simplification-ptr-bool.cl - if (!Ty->isReferenceType()) - return makeNonLoc(Sym, BO_NE, BasicVals.getZeroWithTypeSize(Ty), - CastTy); + SVal VisitLocGotoLabel(loc::GotoLabel V) { + // Pointer to bool. + if (CastTy->isBooleanType()) + // Labels are always true. + return VB.makeTruthVal(true, CastTy); + + // Pointer to integer. + if (CastTy->isIntegralOrEnumerationType()) { + const unsigned BitWidth = Context.getIntWidth(CastTy); + return VB.makeLocAsInteger(V, BitWidth); } - // Non-symbolic memory regions are always true. - return makeTruthVal(true, CastTy); - } - const bool IsUnknownOriginalType = OriginalTy.isNull(); - // Try to cast to array - const auto *ArrayTy = - IsUnknownOriginalType - ? nullptr - : dyn_cast<ArrayType>(OriginalTy.getCanonicalType()); - - // Pointer to integer. - if (CastTy->isIntegralOrEnumerationType()) { - SVal Val = V; - // Array to integer. - if (ArrayTy) { - // We will always decay to a pointer. - QualType ElemTy = ArrayTy->getElementType(); - Val = StateMgr.ArrayToPointer(V, ElemTy); - // FIXME: Keep these here for now in case we decide soon that we - // need the original decayed type. - // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); - // QualType pointerTy = C.getPointerType(elemTy); + const bool IsUnknownOriginalType = OriginalTy.isNull(); + if (!IsUnknownOriginalType) { + // Array to pointer. + if (isa<ArrayType>(OriginalTy)) + if (CastTy->isPointerType() || CastTy->isReferenceType()) + return UnknownVal(); } - const unsigned BitWidth = Context.getIntWidth(CastTy); - return makeLocAsInteger(Val.castAs<Loc>(), BitWidth); - } - // Pointer to pointer. - if (Loc::isLocType(CastTy)) { - - if (IsUnknownOriginalType) { - // When retrieving symbolic pointer and expecting a non-void pointer, - // wrap them into element regions of the expected type if necessary. - // It is necessary to make sure that the retrieved value makes sense, - // because there's no other cast in the AST that would tell us to cast - // it to the correct pointer type. We might need to do that for non-void - // pointers as well. - // FIXME: We really need a single good function to perform casts for us - // correctly every time we need it. + // Pointer to any pointer. + if (Loc::isLocType(CastTy)) + return V; + + // Pointer to whatever else. + return UnknownVal(); + } + SVal VisitLocMemRegionVal(loc::MemRegionVal V) { + // Pointer to bool. + if (CastTy->isBooleanType()) { const MemRegion *R = V.getRegion(); - if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) { - if (const auto *SR = dyn_cast<SymbolicRegion>(R)) { - QualType SRTy = SR->getSymbol()->getType(); - if (!hasSameUnqualifiedPointeeType(SRTy, CastTy)) { - if (auto OptMemRegV = getCastedMemRegionVal(SR, CastTy)) - return *OptMemRegV; - } - } - } - // Next fixes pointer dereference using type different from its initial - // one. See PR37503 and PR49007 for details. - if (const auto *ER = dyn_cast<ElementRegion>(R)) { - if (auto OptMemRegV = getCastedMemRegionVal(ER, CastTy)) - return *OptMemRegV; + if (const FunctionCodeRegion *FTR = dyn_cast<FunctionCodeRegion>(R)) + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(FTR->getDecl())) + if (FD->isWeak()) + // FIXME: Currently we are using an extent symbol here, + // because there are no generic region address metadata + // symbols to use, only content metadata. + return nonloc::SymbolVal( + VB.getSymbolManager().getExtentSymbol(FTR)); + + if (const SymbolicRegion *SymR = R->getSymbolicBase()) { + SymbolRef Sym = SymR->getSymbol(); + QualType Ty = Sym->getType(); + // This change is needed for architectures with varying + // pointer widths. See the amdgcn opencl reproducer with + // this change as an example: solver-sym-simplification-ptr-bool.cl + if (!Ty->isReferenceType()) + return VB.makeNonLoc( + Sym, BO_NE, VB.getBasicValueFactory().getZeroWithTypeSize(Ty), + CastTy); } - - return V; + // Non-symbolic memory regions are always true. + return VB.makeTruthVal(true, CastTy); } - if (OriginalTy->isIntegralOrEnumerationType() || - OriginalTy->isBlockPointerType() || OriginalTy->isFunctionPointerType()) - return V; - - // Array to pointer. - if (ArrayTy) { - // Are we casting from an array to a pointer? If so just pass on - // the decayed value. - if (CastTy->isPointerType() || CastTy->isReferenceType()) { + const bool IsUnknownOriginalType = OriginalTy.isNull(); + // Try to cast to array + const auto *ArrayTy = + IsUnknownOriginalType + ? nullptr + : dyn_cast<ArrayType>(OriginalTy.getCanonicalType()); + + // Pointer to integer. + if (CastTy->isIntegralOrEnumerationType()) { + SVal Val = V; + // Array to integer. + if (ArrayTy) { // We will always decay to a pointer. QualType ElemTy = ArrayTy->getElementType(); - return StateMgr.ArrayToPointer(V, ElemTy); + Val = VB.getStateManager().ArrayToPointer(V, ElemTy); + // FIXME: Keep these here for now in case we decide soon that we + // need the original decayed type. + // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); + // QualType pointerTy = C.getPointerType(elemTy); } - // Are we casting from an array to an integer? If so, cast the decayed - // pointer value to an integer. - assert(CastTy->isIntegralOrEnumerationType()); + const unsigned BitWidth = Context.getIntWidth(CastTy); + return VB.makeLocAsInteger(Val.castAs<Loc>(), BitWidth); } - // Other pointer to pointer. - assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() || - CastTy->isReferenceType()); + // Pointer to pointer. + if (Loc::isLocType(CastTy)) { - // We get a symbolic function pointer for a dereference of a function - // pointer, but it is of function type. Example: + if (IsUnknownOriginalType) { + // When retrieving symbolic pointer and expecting a non-void pointer, + // wrap them into element regions of the expected type if necessary. + // It is necessary to make sure that the retrieved value makes sense, + // because there's no other cast in the AST that would tell us to cast + // it to the correct pointer type. We might need to do that for non-void + // pointers as well. + // FIXME: We really need a single good function to perform casts for us + // correctly every time we need it. + const MemRegion *R = V.getRegion(); + if (CastTy->isPointerType() && !CastTy->isVoidPointerType()) { + if (const auto *SR = dyn_cast<SymbolicRegion>(R)) { + QualType SRTy = SR->getSymbol()->getType(); + + auto HasSameUnqualifiedPointeeType = [](QualType ty1, + QualType ty2) { + return ty1->getPointeeType().getCanonicalType().getTypePtr() == + ty2->getPointeeType().getCanonicalType().getTypePtr(); + }; + if (!HasSameUnqualifiedPointeeType(SRTy, CastTy)) { + if (auto OptMemRegV = VB.getCastedMemRegionVal(SR, CastTy)) + return *OptMemRegV; + } + } + } + // Next fixes pointer dereference using type different from its initial + // one. See PR37503 and PR49007 for details. + if (const auto *ER = dyn_cast<ElementRegion>(R)) { + if (auto OptMemRegV = VB.getCastedMemRegionVal(ER, CastTy)) + return *OptMemRegV; + } - // struct FPRec { - // void (*my_func)(int * x); - // }; - // - // int bar(int x); - // - // int f1_a(struct FPRec* foo) { - // int x; - // (*foo->my_func)(&x); - // return bar(x)+1; // no-warning - // } - - // Get the result of casting a region to a different type. - const MemRegion *R = V.getRegion(); - if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy)) - return *OptMemRegV; - } + return V; + } - // Pointer to whatever else. - // FIXME: There can be gross cases where one casts the result of a - // function (that returns a pointer) to some other value that happens to - // fit within that pointer value. We currently have no good way to model - // such operations. When this happens, the underlying operation is that - // the caller is reasoning about bits. Conceptually we are layering a - // "view" of a location on top of those bits. Perhaps we need to be more - // lazy about mutual possible views, even on an SVal? This may be - // necessary for bit-level reasoning as well. - return UnknownVal(); -} + if (OriginalTy->isIntegralOrEnumerationType() || + OriginalTy->isBlockPointerType() || + OriginalTy->isFunctionPointerType()) + return V; -SVal SValBuilder::evalCastSubKind(nonloc::CompoundVal V, QualType CastTy, - QualType OriginalTy) { - // Compound to whatever. - return UnknownVal(); -} + // Array to pointer. + if (ArrayTy) { + // Are we casting from an array to a pointer? If so just pass on + // the decayed value. + if (CastTy->isPointerType() || CastTy->isReferenceType()) { + // We will always decay to a pointer. + QualType ElemTy = ArrayTy->getElementType(); + return VB.getStateManager().ArrayToPointer(V, ElemTy); + } + // Are we casting from an array to an integer? If so, cast the decayed + // pointer value to an integer. + assert(CastTy->isIntegralOrEnumerationType()); + } -SVal SValBuilder::evalCastSubKind(nonloc::ConcreteInt V, QualType CastTy, - QualType OriginalTy) { - auto CastedValue = [V, CastTy, this]() { - llvm::APSInt Value = V.getValue(); - BasicVals.getAPSIntType(CastTy).apply(Value); - return Value; - }; + // Other pointer to pointer. + assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() || + CastTy->isReferenceType()); - // Integer to bool. - if (CastTy->isBooleanType()) - return makeTruthVal(V.getValue().getBoolValue(), CastTy); + // We get a symbolic function pointer for a dereference of a function + // pointer, but it is of function type. Example: + + // struct FPRec { + // void (*my_func)(int * x); + // }; + // + // int bar(int x); + // + // int f1_a(struct FPRec* foo) { + // int x; + // (*foo->my_func)(&x); + // return bar(x)+1; // no-warning + // } + + // Get the result of casting a region to a different type. + const MemRegion *R = V.getRegion(); + if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy)) + return *OptMemRegV; + } - // Integer to pointer. - if (CastTy->isIntegralOrEnumerationType()) - return makeIntVal(CastedValue()); + // Pointer to whatever else. + // FIXME: There can be gross cases where one casts the result of a + // function (that returns a pointer) to some other value that happens to + // fit within that pointer value. We currently have no good way to model + // such operations. When this happens, the underlying operation is that + // the caller is reasoning about bits. Conceptually we are layering a + // "view" of a location on top of those bits. Perhaps we need to be more + // lazy about mutual possible views, even on an SVal? This may be + // necessary for bit-level reasoning as well. + return UnknownVal(); + } + SVal VisitNonLocCompoundVal(nonloc::CompoundVal V) { + // Compound to whatever. + return UnknownVal(); + } + SVal VisitNonLocConcreteInt(nonloc::ConcreteInt V) { + auto CastedValue = [V, this]() { + llvm::APSInt Value = V.getValue(); + VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value); + return Value; + }; - // Integer to pointer. - if (Loc::isLocType(CastTy)) - return makeIntLocVal(CastedValue()); + // Integer to bool. + if (CastTy->isBooleanType()) + return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy); - // Pointer to whatever else. - return UnknownVal(); -} + // Integer to pointer. + if (CastTy->isIntegralOrEnumerationType()) + return VB.makeIntVal(CastedValue()); -SVal SValBuilder::evalCastSubKind(nonloc::LazyCompoundVal V, QualType CastTy, - QualType OriginalTy) { - // Compound to whatever. - return UnknownVal(); -} + // Integer to pointer. + if (Loc::isLocType(CastTy)) + return VB.makeIntLocVal(CastedValue()); -SVal SValBuilder::evalCastSubKind(nonloc::LocAsInteger V, QualType CastTy, - QualType OriginalTy) { - Loc L = V.getLoc(); - - // Pointer as integer to bool. - if (CastTy->isBooleanType()) - // Pass to Loc function. - return evalCastKind(L, CastTy, OriginalTy); - - const bool IsUnknownOriginalType = OriginalTy.isNull(); - // Pointer as integer to pointer. - if (!IsUnknownOriginalType && Loc::isLocType(CastTy) && - OriginalTy->isIntegralOrEnumerationType()) { - if (const MemRegion *R = L.getAsRegion()) - if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy)) - return *OptMemRegV; - return L; + // Pointer to whatever else. + return UnknownVal(); } - - // Pointer as integer with region to integer/pointer. - const MemRegion *R = L.getAsRegion(); - if (!IsUnknownOriginalType && R) { - if (CastTy->isIntegralOrEnumerationType()) - return evalCastSubKind(loc::MemRegionVal(R), CastTy, OriginalTy); - - if (Loc::isLocType(CastTy)) { - assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() || - CastTy->isReferenceType()); - // Delegate to store manager to get the result of casting a region to a - // different type. If the MemRegion* returned is NULL, this expression - // Evaluates to UnknownVal. - if (auto OptMemRegV = getCastedMemRegionVal(R, CastTy)) - return *OptMemRegV; - } - } else { - if (Loc::isLocType(CastTy)) { - if (IsUnknownOriginalType) - return evalCastSubKind(loc::MemRegionVal(R), CastTy, OriginalTy); + SVal VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) { + // LazyCompound to whatever. + return UnknownVal(); + } + SVal VisitNonLocLocAsInteger(nonloc::LocAsInteger V) { + Loc L = V.getLoc(); + + // Pointer as integer to bool. + if (CastTy->isBooleanType()) + // Pass to Loc function. + return Visit(L); + + const bool IsUnknownOriginalType = OriginalTy.isNull(); + // Pointer as integer to pointer. + if (!IsUnknownOriginalType && Loc::isLocType(CastTy) && + OriginalTy->isIntegralOrEnumerationType()) { + if (const MemRegion *R = L.getAsRegion()) + if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy)) + return *OptMemRegV; return L; } - SymbolRef SE = nullptr; - if (R) { - if (const SymbolicRegion *SR = - dyn_cast<SymbolicRegion>(R->StripCasts())) { - SE = SR->getSymbol(); + // Pointer as integer with region to integer/pointer. + const MemRegion *R = L.getAsRegion(); + if (!IsUnknownOriginalType && R) { + if (CastTy->isIntegralOrEnumerationType()) + return VisitLocMemRegionVal(loc::MemRegionVal(R)); + + if (Loc::isLocType(CastTy)) { + assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() || + CastTy->isReferenceType()); + // Delegate to store manager to get the result of casting a region to a + // different type. If the MemRegion* returned is NULL, this expression + // Evaluates to UnknownVal. + if (auto OptMemRegV = VB.getCastedMemRegionVal(R, CastTy)) + return *OptMemRegV; + } + } else { + if (Loc::isLocType(CastTy)) { + if (IsUnknownOriginalType) + return VisitLocMemRegionVal(loc::MemRegionVal(R)); + return L; } - } - - if (!CastTy->isFloatingType() || !SE || SE->getType()->isFloatingType()) { - // FIXME: Correctly support promotions/truncations. - const unsigned CastSize = Context.getIntWidth(CastTy); - if (CastSize == V.getNumBits()) - return V; - return makeLocAsInteger(L, CastSize); - } - } + SymbolRef SE = nullptr; + if (R) { + if (const SymbolicRegion *SR = + dyn_cast<SymbolicRegion>(R->StripCasts())) { + SE = SR->getSymbol(); + } + } - // Pointer as integer to whatever else. - return UnknownVal(); -} + if (!CastTy->isFloatingType() || !SE || SE->getType()->isFloatingType()) { + // FIXME: Correctly support promotions/truncations. + const unsigned CastSize = Context.getIntWidth(CastTy); + if (CastSize == V.getNumBits()) + return V; -SVal SValBuilder::evalCastSubKind(nonloc::SymbolVal V, QualType CastTy, - QualType OriginalTy) { - SymbolRef SE = V.getSymbol(); - - const bool IsUnknownOriginalType = OriginalTy.isNull(); - // Symbol to bool. - if (!IsUnknownOriginalType && CastTy->isBooleanType()) { - // Non-float to bool. - if (Loc::isLocType(OriginalTy) || - OriginalTy->isIntegralOrEnumerationType() || - OriginalTy->isMemberPointerType()) { - BasicValueFactory &BVF = getBasicValueFactory(); - return makeNonLoc(SE, BO_NE, BVF.getValue(0, SE->getType()), CastTy); + return VB.makeLocAsInteger(L, CastSize); + } } - } else { - // Symbol to integer, float. - QualType T = Context.getCanonicalType(SE->getType()); - // Produce SymbolCast if CastTy and T are different integers. - // NOTE: In the end the type of SymbolCast shall be equal to CastTy. - if (T->isIntegralOrUnscopedEnumerationType() && - CastTy->isIntegralOrUnscopedEnumerationType()) { - AnalyzerOptions &Opts = - StateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions(); - // If appropriate option is disabled, ignore the cast. - // NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default. - if (!Opts.ShouldSupportSymbolicIntegerCasts) - return V; - return simplifySymbolCast(V, CastTy); + // Pointer as integer to whatever else. + return UnknownVal(); + } + SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) { + SymbolRef SE = V.getSymbol(); + + const bool IsUnknownOriginalType = OriginalTy.isNull(); + // Symbol to bool. + if (!IsUnknownOriginalType && CastTy->isBooleanType()) { + // Non-float to bool. + if (Loc::isLocType(OriginalTy) || + OriginalTy->isIntegralOrEnumerationType() || + OriginalTy->isMemberPointerType()) { + BasicValueFactory &BVF = VB.getBasicValueFactory(); + return VB.makeNonLoc(SE, BO_NE, BVF.getValue(0, SE->getType()), CastTy); + } + } else { + // Symbol to integer, float. + QualType T = Context.getCanonicalType(SE->getType()); + + // Produce SymbolCast if CastTy and T are different integers. + // NOTE: In the end the type of SymbolCast shall be equal to CastTy. + if (T->isIntegralOrUnscopedEnumerationType() && + CastTy->isIntegralOrUnscopedEnumerationType()) { + AnalyzerOptions &Opts = VB.getStateManager() + .getOwningEngine() + .getAnalysisManager() + .getAnalyzerOptions(); + // If appropriate option is disabled, ignore the cast. + // NOTE: ShouldSupportSymbolicIntegerCasts is `false` by default. + if (!Opts.ShouldSupportSymbolicIntegerCasts) + return V; + return simplifySymbolCast(V, CastTy); + } + if (!Loc::isLocType(CastTy)) + if (!IsUnknownOriginalType || !CastTy->isFloatingType() || + T->isFloatingType()) + return VB.makeNonLoc(SE, T, CastTy); } - if (!Loc::isLocType(CastTy)) - if (!IsUnknownOriginalType || !CastTy->isFloatingType() || - T->isFloatingType()) - return makeNonLoc(SE, T, CastTy); + + // Symbol to pointer and whatever else. + return UnknownVal(); + } + SVal VisitNonLocPointerToMember(nonloc::PointerToMember V) { + // Member pointer to whatever. + return V; } - // Symbol to pointer and whatever else. - return UnknownVal(); -} + /// Reduce cast expression by removing redundant intermediate casts. + /// E.g. + /// - (char)(short)(int x) -> (char)(int x) + /// - (int)(int x) -> int x + /// + /// \param V -- SymbolVal, which pressumably contains SymbolCast or any symbol + /// that is applicable for cast operation. + /// \param CastTy -- QualType, which `V` shall be cast to. + /// \return SVal with simplified cast expression. + /// \note: Currently only support integral casts. + nonloc::SymbolVal simplifySymbolCast(nonloc::SymbolVal V, QualType CastTy) { + // We use seven conditions to recognize a simplification case. + // For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type - + // `R`, prefix `u` for unsigned, `s` for signed, no prefix - any sign: E.g. + // (char)(short)(uint x) + // ( sC )( sT )( uR x) + // + // C === R (the same type) + // (char)(char x) -> (char x) + // (long)(long x) -> (long x) + // Note: Comparisons operators below are for bit width. + // C == T + // (short)(short)(int x) -> (short)(int x) + // (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int)) + // (long)(ullong)(char x) -> (long)(char x) (sizeof(long) == + // sizeof(ullong)) + // C < T + // (short)(int)(char x) -> (short)(char x) + // (char)(int)(short x) -> (char)(short x) + // (short)(int)(short x) -> (short x) + // C > T > uR + // (int)(short)(uchar x) -> (int)(uchar x) + // (uint)(short)(uchar x) -> (uint)(uchar x) + // (int)(ushort)(uchar x) -> (int)(uchar x) + // C > sT > sR + // (int)(short)(char x) -> (int)(char x) + // (uint)(short)(char x) -> (uint)(char x) + // C > sT == sR + // (int)(char)(char x) -> (int)(char x) + // (uint)(short)(short x) -> (uint)(short x) + // C > uT == uR + // (int)(uchar)(uchar x) -> (int)(uchar x) + // (uint)(ushort)(ushort x) -> (uint)(ushort x) + // (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) == + // sizeof(uint)) + + SymbolRef SE = V.getSymbol(); + QualType T = Context.getCanonicalType(SE->getType()); -SVal SValBuilder::evalCastSubKind(nonloc::PointerToMember V, QualType CastTy, - QualType OriginalTy) { - // Member pointer to whatever. - return V; -} + if (T == CastTy) + return V; -nonloc::SymbolVal SValBuilder::simplifySymbolCast(nonloc::SymbolVal V, - QualType CastTy) { - // We use seven conditions to recognize a simplification case. - // For the clarity let `CastTy` be `C`, SE->getType() - `T`, root type - `R`, - // prefix `u` for unsigned, `s` for signed, no prefix - any sign: - // E.g. (char)(short)(uint x) - // ( sC )( sT )( uR x) - // - // C === R (the same type) - // (char)(char x) -> (char x) - // (long)(long x) -> (long x) - // Note: Comparisons operators below are for bit width. - // C == T - // (short)(short)(int x) -> (short)(int x) - // (int)(long)(char x) -> (int)(char x) (sizeof(long) == sizeof(int)) - // (long)(ullong)(char x) -> (long)(char x) (sizeof(long) == sizeof(ullong)) - // C < T - // (short)(int)(char x) -> (short)(char x) - // (char)(int)(short x) -> (char)(short x) - // (short)(int)(short x) -> (short x) - // C > T > uR - // (int)(short)(uchar x) -> (int)(uchar x) - // (uint)(short)(uchar x) -> (uint)(uchar x) - // (int)(ushort)(uchar x) -> (int)(uchar x) - // C > sT > sR - // (int)(short)(char x) -> (int)(char x) - // (uint)(short)(char x) -> (uint)(char x) - // C > sT == sR - // (int)(char)(char x) -> (int)(char x) - // (uint)(short)(short x) -> (uint)(short x) - // C > uT == uR - // (int)(uchar)(uchar x) -> (int)(uchar x) - // (uint)(ushort)(ushort x) -> (uint)(ushort x) - // (llong)(ulong)(uint x) -> (llong)(uint x) (sizeof(ulong) == sizeof(uint)) - - SymbolRef SE = V.getSymbol(); - QualType T = Context.getCanonicalType(SE->getType()); - - if (T == CastTy) - return V; + if (!isa<SymbolCast>(SE)) + return VB.makeNonLoc(SE, T, CastTy); - if (!isa<SymbolCast>(SE)) - return makeNonLoc(SE, T, CastTy); + SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand(); + QualType RT = RootSym->getType().getCanonicalType(); - SymbolRef RootSym = cast<SymbolCast>(SE)->getOperand(); - QualType RT = RootSym->getType().getCanonicalType(); + // FIXME support simplification from non-integers. + if (!RT->isIntegralOrEnumerationType()) + return VB.makeNonLoc(SE, T, CastTy); - // FIXME support simplification from non-integers. - if (!RT->isIntegralOrEnumerationType()) - return makeNonLoc(SE, T, CastTy); + BasicValueFactory &BVF = VB.getBasicValueFactory(); + APSIntType CTy = BVF.getAPSIntType(CastTy); + APSIntType TTy = BVF.getAPSIntType(T); - BasicValueFactory &BVF = getBasicValueFactory(); - APSIntType CTy = BVF.getAPSIntType(CastTy); - APSIntType TTy = BVF.getAPSIntType(T); + const auto WC = CTy.getBitWidth(); + const auto WT = TTy.getBitWidth(); - const auto WC = CTy.getBitWidth(); - const auto WT = TTy.getBitWidth(); + if (WC <= WT) { + const bool isSameType = (RT == CastTy); + if (isSameType) + return nonloc::SymbolVal(RootSym); + return VB.makeNonLoc(RootSym, RT, CastTy); + } - if (WC <= WT) { - const bool isSameType = (RT == CastTy); - if (isSameType) - return nonloc::SymbolVal(RootSym); - return makeNonLoc(RootSym, RT, CastTy); - } + APSIntType RTy = BVF.getAPSIntType(RT); + const auto WR = RTy.getBitWidth(); + const bool UT = TTy.isUnsigned(); + const bool UR = RTy.isUnsigned(); - APSIntType RTy = BVF.getAPSIntType(RT); - const auto WR = RTy.getBitWidth(); - const bool UT = TTy.isUnsigned(); - const bool UR = RTy.isUnsigned(); + if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR))) + return VB.makeNonLoc(RootSym, RT, CastTy); - if (((WT > WR) && (UR || !UT)) || ((WT == WR) && (UT == UR))) - return makeNonLoc(RootSym, RT, CastTy); + return VB.makeNonLoc(SE, T, CastTy); + } +}; +} // end anonymous namespace - return makeNonLoc(SE, T, CastTy); +/// Cast a given SVal to another SVal using given QualType's. +/// \param V -- SVal that should be casted. +/// \param CastTy -- QualType that V should be casted according to. +/// \param OriginalTy -- QualType which is associated to V. It provides +/// additional information about what type the cast performs from. +/// \returns the most appropriate casted SVal. +/// Note: Many cases don't use an exact OriginalTy. It can be extracted +/// from SVal or the cast can performs unconditionaly. Always pass OriginalTy! +/// It can be crucial in certain cases and generates different results. +/// FIXME: If `OriginalTy.isNull()` is true, then cast performs based on CastTy +/// only. This behavior is uncertain and should be improved. +SVal SValBuilder::evalCast(SVal V, QualType CastTy, QualType OriginalTy) { + EvalCastVisitor TRV{*this, CastTy, OriginalTy}; + return TRV.Visit(V); } diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp index 67913a55b3dc..31725926cd0d 100644 --- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp +++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp @@ -109,6 +109,14 @@ SymbolRef SVal::getAsSymbol(bool IncludeBaseRegions) const { return getAsLocSymbol(IncludeBaseRegions); } +const llvm::APSInt *SVal::getAsInteger() const { + if (auto CI = getAs<nonloc::ConcreteInt>()) + return &CI->getValue(); + if (auto CI = getAs<loc::ConcreteInt>()) + return &CI->getValue(); + return nullptr; +} + const MemRegion *SVal::getAsRegion() const { if (Optional<loc::MemRegionVal> X = getAs<loc::MemRegionVal>()) return X->getRegion(); @@ -136,6 +144,8 @@ public: } template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) { const llvm::APSInt &Value = CI.getValue(); + if (1 == Value.getBitWidth()) + return Context.BoolTy; return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned()); } QualType VisitLocConcreteInt(loc::ConcreteInt CI) { diff --git a/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp index 43127ea2df98..411fd9676ffd 100644 --- a/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -50,8 +50,9 @@ FullDependencies::getCommandLineWithoutModulePaths() const { } DependencyScanningTool::DependencyScanningTool( - DependencyScanningService &Service) - : Worker(Service) {} + DependencyScanningService &Service, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : Worker(Service, std::move(FS)) {} llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( const std::vector<std::string> &CommandLine, StringRef CWD, diff --git a/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index e7d1375c83f0..474808d888ec 100644 --- a/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -264,7 +264,8 @@ private: } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( - DependencyScanningService &Service) + DependencyScanningService &Service, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) { PCHContainerOps = std::make_shared<PCHContainerOperations>(); PCHContainerOps->registerReader( @@ -274,8 +275,8 @@ DependencyScanningWorker::DependencyScanningWorker( PCHContainerOps->registerWriter( std::make_unique<ObjectFilePCHContainerWriter>()); - auto OverlayFS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>( - llvm::vfs::createPhysicalFileSystem()); + auto OverlayFS = + llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(std::move(FS)); InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>(); OverlayFS->pushOverlay(InMemoryFS); RealFS = OverlayFS; diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/BuildTree.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/BuildTree.cpp index 484cf61664fe..041cc4f939d9 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -27,6 +27,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Tooling/Syntax/Nodes.h" +#include "clang/Tooling/Syntax/TokenBufferTokenManager.h" #include "clang/Tooling/Syntax/Tokens.h" #include "clang/Tooling/Syntax/Tree.h" #include "llvm/ADT/ArrayRef.h" @@ -365,21 +366,24 @@ private: /// Call finalize() to finish building the tree and consume the root node. class syntax::TreeBuilder { public: - TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) { - for (const auto &T : Arena.getTokenBuffer().expandedTokens()) + TreeBuilder(syntax::Arena &Arena, TokenBufferTokenManager& TBTM) + : Arena(Arena), + TBTM(TBTM), + Pending(Arena, TBTM.tokenBuffer()) { + for (const auto &T : TBTM.tokenBuffer().expandedTokens()) LocationToToken.insert({T.location(), &T}); } llvm::BumpPtrAllocator &allocator() { return Arena.getAllocator(); } const SourceManager &sourceManager() const { - return Arena.getSourceManager(); + return TBTM.sourceManager(); } /// Populate children for \p New node, assuming it covers tokens from \p /// Range. void foldNode(ArrayRef<syntax::Token> Range, syntax::Tree *New, ASTPtr From) { assert(New); - Pending.foldChildren(Arena, Range, New); + Pending.foldChildren(TBTM.tokenBuffer(), Range, New); if (From) Mapping.add(From, New); } @@ -392,7 +396,7 @@ public: void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New, NestedNameSpecifierLoc From) { assert(New); - Pending.foldChildren(Arena, Range, New); + Pending.foldChildren(TBTM.tokenBuffer(), Range, New); if (From) Mapping.add(From, New); } @@ -403,7 +407,7 @@ public: ASTPtr From) { assert(New); auto ListRange = Pending.shrinkToFitList(SuperRange); - Pending.foldChildren(Arena, ListRange, New); + Pending.foldChildren(TBTM.tokenBuffer(), ListRange, New); if (From) Mapping.add(From, New); } @@ -434,12 +438,12 @@ public: /// Finish building the tree and consume the root node. syntax::TranslationUnit *finalize() && { - auto Tokens = Arena.getTokenBuffer().expandedTokens(); + auto Tokens = TBTM.tokenBuffer().expandedTokens(); assert(!Tokens.empty()); assert(Tokens.back().kind() == tok::eof); // Build the root of the tree, consuming all the children. - Pending.foldChildren(Arena, Tokens.drop_back(), + Pending.foldChildren(TBTM.tokenBuffer(), Tokens.drop_back(), new (Arena.getAllocator()) syntax::TranslationUnit); auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize()); @@ -464,7 +468,7 @@ public: assert(First.isValid()); assert(Last.isValid()); assert(First == Last || - Arena.getSourceManager().isBeforeInTranslationUnit(First, Last)); + TBTM.sourceManager().isBeforeInTranslationUnit(First, Last)); return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); } @@ -564,15 +568,16 @@ private: /// /// Ensures that added nodes properly nest and cover the whole token stream. struct Forest { - Forest(syntax::Arena &A) { - assert(!A.getTokenBuffer().expandedTokens().empty()); - assert(A.getTokenBuffer().expandedTokens().back().kind() == tok::eof); + Forest(syntax::Arena &A, const syntax::TokenBuffer &TB) { + assert(!TB.expandedTokens().empty()); + assert(TB.expandedTokens().back().kind() == tok::eof); // Create all leaf nodes. // Note that we do not have 'eof' in the tree. - for (const auto &T : A.getTokenBuffer().expandedTokens().drop_back()) { - auto *L = new (A.getAllocator()) syntax::Leaf(&T); + for (const auto &T : TB.expandedTokens().drop_back()) { + auto *L = new (A.getAllocator()) + syntax::Leaf(reinterpret_cast<TokenManager::Key>(&T)); L->Original = true; - L->CanModify = A.getTokenBuffer().spelledForExpanded(T).has_value(); + L->CanModify = TB.spelledForExpanded(T).has_value(); Trees.insert(Trees.end(), {&T, L}); } } @@ -620,8 +625,8 @@ private: } /// Add \p Node to the forest and attach child nodes based on \p Tokens. - void foldChildren(const syntax::Arena &A, ArrayRef<syntax::Token> Tokens, - syntax::Tree *Node) { + void foldChildren(const syntax::TokenBuffer &TB, + ArrayRef<syntax::Token> Tokens, syntax::Tree *Node) { // Attach children to `Node`. assert(Node->getFirstChild() == nullptr && "node already has children"); @@ -646,7 +651,7 @@ private: // Mark that this node came from the AST and is backed by the source code. Node->Original = true; Node->CanModify = - A.getTokenBuffer().spelledForExpanded(Tokens).has_value(); + TB.spelledForExpanded(Tokens).has_value(); Trees.erase(BeginChildren, EndChildren); Trees.insert({FirstToken, Node}); @@ -660,18 +665,18 @@ private: return Root; } - std::string str(const syntax::Arena &A) const { + std::string str(const syntax::TokenBufferTokenManager &STM) const { std::string R; for (auto It = Trees.begin(); It != Trees.end(); ++It) { unsigned CoveredTokens = It != Trees.end() ? (std::next(It)->first - It->first) - : A.getTokenBuffer().expandedTokens().end() - It->first; + : STM.tokenBuffer().expandedTokens().end() - It->first; R += std::string( formatv("- '{0}' covers '{1}'+{2} tokens\n", It->second->getKind(), - It->first->text(A.getSourceManager()), CoveredTokens)); - R += It->second->dump(A.getSourceManager()); + It->first->text(STM.sourceManager()), CoveredTokens)); + R += It->second->dump(STM); } return R; } @@ -684,9 +689,10 @@ private: }; /// For debugging purposes. - std::string str() { return Pending.str(Arena); } + std::string str() { return Pending.str(TBTM); } syntax::Arena &Arena; + TokenBufferTokenManager& TBTM; /// To quickly find tokens by their start location. llvm::DenseMap<SourceLocation, const syntax::Token *> LocationToToken; Forest Pending; @@ -1718,7 +1724,7 @@ void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { markExprChild(ChildExpr, NodeRole::Expression); ChildNode = new (allocator()) syntax::ExpressionStatement; // (!) 'getStmtRange()' ensures this covers a trailing semicolon. - Pending.foldChildren(Arena, getStmtRange(Child), ChildNode); + Pending.foldChildren(TBTM.tokenBuffer(), getStmtRange(Child), ChildNode); } else { ChildNode = Mapping.find(Child); } @@ -1745,8 +1751,9 @@ const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { } syntax::TranslationUnit *syntax::buildSyntaxTree(Arena &A, + TokenBufferTokenManager& TBTM, ASTContext &Context) { - TreeBuilder Builder(A); + TreeBuilder Builder(A, TBTM); BuildTreeVisitor(Context, Builder).TraverseAST(Context); return std::move(Builder).finalize(); } diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/ComputeReplacements.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/ComputeReplacements.cpp index 31e1a40c74b6..08e09e4ebdbf 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/ComputeReplacements.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/ComputeReplacements.cpp @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/Core/Replacement.h" #include "clang/Tooling/Syntax/Mutations.h" +#include "clang/Tooling/Syntax/TokenBufferTokenManager.h" #include "clang/Tooling/Syntax/Tokens.h" +#include "clang/Tooling/Syntax/Tree.h" #include "llvm/Support/Error.h" using namespace clang; @@ -16,10 +18,13 @@ namespace { using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>, bool /*IsOriginal*/)>; /// Enumerates spans of tokens from the tree consecutively laid out in memory. -void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) { +void enumerateTokenSpans(const syntax::Tree *Root, + const syntax::TokenBufferTokenManager &STM, + ProcessTokensFn Callback) { struct Enumerator { - Enumerator(ProcessTokensFn Callback) - : SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false), + Enumerator(const syntax::TokenBufferTokenManager &STM, + ProcessTokensFn Callback) + : STM(STM), SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false), Callback(Callback) {} void run(const syntax::Tree *Root) { @@ -39,7 +44,8 @@ void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) { } auto *L = cast<syntax::Leaf>(N); - if (SpanEnd == L->getToken() && SpanIsOriginal == L->isOriginal()) { + if (SpanEnd == STM.getToken(L->getTokenKey()) && + SpanIsOriginal == L->isOriginal()) { // Extend the current span. ++SpanEnd; return; @@ -48,24 +54,25 @@ void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) { if (SpanBegin) Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal); // Start recording a new span. - SpanBegin = L->getToken(); + SpanBegin = STM.getToken(L->getTokenKey()); SpanEnd = SpanBegin + 1; SpanIsOriginal = L->isOriginal(); } + const syntax::TokenBufferTokenManager &STM; const syntax::Token *SpanBegin; const syntax::Token *SpanEnd; bool SpanIsOriginal; ProcessTokensFn Callback; }; - return Enumerator(Callback).run(Root); + return Enumerator(STM, Callback).run(Root); } -syntax::FileRange rangeOfExpanded(const syntax::Arena &A, +syntax::FileRange rangeOfExpanded(const syntax::TokenBufferTokenManager &STM, llvm::ArrayRef<syntax::Token> Expanded) { - const auto &Buffer = A.getTokenBuffer(); - const auto &SM = A.getSourceManager(); + const auto &Buffer = STM.tokenBuffer(); + const auto &SM = STM.sourceManager(); // Check that \p Expanded actually points into expanded tokens. assert(Buffer.expandedTokens().begin() <= Expanded.begin()); @@ -83,10 +90,10 @@ syntax::FileRange rangeOfExpanded(const syntax::Arena &A, } // namespace tooling::Replacements -syntax::computeReplacements(const syntax::Arena &A, +syntax::computeReplacements(const TokenBufferTokenManager &TBTM, const syntax::TranslationUnit &TU) { - const auto &Buffer = A.getTokenBuffer(); - const auto &SM = A.getSourceManager(); + const auto &Buffer = TBTM.tokenBuffer(); + const auto &SM = TBTM.sourceManager(); tooling::Replacements Replacements; // Text inserted by the replacement we are building now. @@ -95,13 +102,13 @@ syntax::computeReplacements(const syntax::Arena &A, if (ReplacedRange.empty() && Replacement.empty()) return; llvm::cantFail(Replacements.add(tooling::Replacement( - SM, rangeOfExpanded(A, ReplacedRange).toCharRange(SM), Replacement))); + SM, rangeOfExpanded(TBTM, ReplacedRange).toCharRange(SM), + Replacement))); Replacement = ""; }; - const syntax::Token *NextOriginal = Buffer.expandedTokens().begin(); enumerateTokenSpans( - &TU, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) { + &TU, TBTM, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) { if (!IsOriginal) { Replacement += syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM); diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp index f8a652219b22..824f1942532d 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp @@ -77,7 +77,8 @@ public: } }; -void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) { +void syntax::removeStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM, + syntax::Statement *S) { assert(S); assert(S->canModify()); @@ -90,5 +91,5 @@ void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) { if (isa<EmptyStatement>(S)) return; // already an empty statement, nothing to do. - MutationsImpl::replace(S, createEmptyStatement(A)); + MutationsImpl::replace(S, createEmptyStatement(A, TBTM)); } diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/Nodes.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/Nodes.cpp index fc6f8ef1a82c..d0c1e9297cfa 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/Nodes.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// #include "clang/Tooling/Syntax/Nodes.h" -#include "clang/Basic/TokenKinds.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/Synthesis.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/Synthesis.cpp index ef6492882be6..39c19951ae76 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/Synthesis.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/Synthesis.cpp @@ -8,6 +8,8 @@ #include "clang/Basic/TokenKinds.h" #include "clang/Tooling/Syntax/BuildTree.h" #include "clang/Tooling/Syntax/Tree.h" +#include "clang/Tooling/Syntax/Tokens.h" +#include "clang/Tooling/Syntax/TokenBufferTokenManager.h" using namespace clang; @@ -27,35 +29,40 @@ public: } static std::pair<FileID, ArrayRef<Token>> - lexBuffer(syntax::Arena &A, std::unique_ptr<llvm::MemoryBuffer> Buffer) { - return A.lexBuffer(std::move(Buffer)); + lexBuffer(TokenBufferTokenManager &TBTM, + std::unique_ptr<llvm::MemoryBuffer> Buffer) { + return TBTM.lexBuffer(std::move(Buffer)); } }; // FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it // doesn't support digraphs or line continuations. -syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K, - StringRef Spelling) { +syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, + TokenBufferTokenManager &TBTM, + tok::TokenKind K, StringRef Spelling) { auto Tokens = - FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBufferCopy(Spelling)) + FactoryImpl::lexBuffer(TBTM, llvm::MemoryBuffer::getMemBufferCopy(Spelling)) .second; assert(Tokens.size() == 1); assert(Tokens.front().kind() == K && "spelling is not lexed into the expected kind of token"); - auto *Leaf = new (A.getAllocator()) syntax::Leaf(Tokens.begin()); + auto *Leaf = new (A.getAllocator()) syntax::Leaf( + reinterpret_cast<TokenManager::Key>(Tokens.begin())); syntax::FactoryImpl::setCanModify(Leaf); Leaf->assertInvariants(); return Leaf; } -syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K) { +syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, + TokenBufferTokenManager &TBTM, + tok::TokenKind K) { const auto *Spelling = tok::getPunctuatorSpelling(K); if (!Spelling) Spelling = tok::getKeywordSpelling(K); assert(Spelling && "Cannot infer the spelling of the token from its token kind."); - return createLeaf(A, K, Spelling); + return createLeaf(A, TBTM, K, Spelling); } namespace { @@ -208,24 +215,25 @@ syntax::Tree *clang::syntax::createTree( } syntax::Node *clang::syntax::deepCopyExpandingMacros(syntax::Arena &A, + TokenBufferTokenManager &TBTM, const syntax::Node *N) { if (const auto *L = dyn_cast<syntax::Leaf>(N)) // `L->getToken()` gives us the expanded token, thus we implicitly expand // any macros here. - return createLeaf(A, L->getToken()->kind(), - L->getToken()->text(A.getSourceManager())); + return createLeaf(A, TBTM, TBTM.getToken(L->getTokenKey())->kind(), + TBTM.getText(L->getTokenKey())); const auto *T = cast<syntax::Tree>(N); std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children; for (const auto *Child = T->getFirstChild(); Child; Child = Child->getNextSibling()) - Children.push_back({deepCopyExpandingMacros(A, Child), Child->getRole()}); + Children.push_back({deepCopyExpandingMacros(A, TBTM, Child), Child->getRole()}); return createTree(A, Children, N->getKind()); } -syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) { +syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM) { return cast<EmptyStatement>( - createTree(A, {{createLeaf(A, tok::semi), NodeRole::Unknown}}, + createTree(A, {{createLeaf(A, TBTM, tok::semi), NodeRole::Unknown}}, NodeKind::EmptyStatement)); } diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp new file mode 100644 index 000000000000..a06f7e2900d4 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/TokenBufferTokenManager.cpp @@ -0,0 +1,25 @@ +//===- TokenBufferTokenManager.cpp ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Syntax/TokenBufferTokenManager.h" + +namespace clang { +namespace syntax { +constexpr llvm::StringLiteral syntax::TokenBufferTokenManager::Kind; + +std::pair<FileID, ArrayRef<syntax::Token>> +syntax::TokenBufferTokenManager::lexBuffer( + std::unique_ptr<llvm::MemoryBuffer> Input) { + auto FID = SM.createFileID(std::move(Input)); + auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SM, LangOpts)); + assert(It.second && "duplicate FileID"); + return {FID, It.first->second}; +} + +} // namespace syntax +} // namespace clang diff --git a/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp b/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp index 981bac508f73..20f7bd087aa0 100644 --- a/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp +++ b/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp @@ -8,9 +8,8 @@ #include "clang/Tooling/Syntax/Tree.h" #include "clang/Basic/TokenKinds.h" #include "clang/Tooling/Syntax/Nodes.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Casting.h" #include <cassert> @@ -33,25 +32,7 @@ static void traverse(syntax::Node *N, } } // namespace -syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts, - const TokenBuffer &Tokens) - : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(Tokens) {} - -const syntax::TokenBuffer &syntax::Arena::getTokenBuffer() const { - return Tokens; -} - -std::pair<FileID, ArrayRef<syntax::Token>> -syntax::Arena::lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input) { - auto FID = SourceMgr.createFileID(std::move(Input)); - auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SourceMgr, LangOpts)); - assert(It.second && "duplicate FileID"); - return {FID, It.first->second}; -} - -syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) { - assert(Tok != nullptr); -} +syntax::Leaf::Leaf(syntax::TokenManager::Key K) : Node(NodeKind::Leaf), K(K) {} syntax::Node::Node(NodeKind Kind) : Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr), @@ -190,20 +171,8 @@ void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End, } namespace { -static void dumpLeaf(raw_ostream &OS, const syntax::Leaf *L, - const SourceManager &SM) { - assert(L); - const auto *Token = L->getToken(); - assert(Token); - // Handle 'eof' separately, calling text() on it produces an empty string. - if (Token->kind() == tok::eof) - OS << "<eof>"; - else - OS << Token->text(SM); -} - static void dumpNode(raw_ostream &OS, const syntax::Node *N, - const SourceManager &SM, llvm::BitVector IndentMask) { + const syntax::TokenManager &TM, llvm::BitVector IndentMask) { auto DumpExtraInfo = [&OS](const syntax::Node *N) { if (N->getRole() != syntax::NodeRole::Unknown) OS << " " << N->getRole(); @@ -216,7 +185,7 @@ static void dumpNode(raw_ostream &OS, const syntax::Node *N, assert(N); if (const auto *L = dyn_cast<syntax::Leaf>(N)) { OS << "'"; - dumpLeaf(OS, L, SM); + OS << TM.getText(L->getTokenKey()); OS << "'"; DumpExtraInfo(N); OS << "\n"; @@ -242,25 +211,25 @@ static void dumpNode(raw_ostream &OS, const syntax::Node *N, OS << "|-"; IndentMask.push_back(true); } - dumpNode(OS, &It, SM, IndentMask); + dumpNode(OS, &It, TM, IndentMask); IndentMask.pop_back(); } } } // namespace -std::string syntax::Node::dump(const SourceManager &SM) const { +std::string syntax::Node::dump(const TokenManager &TM) const { std::string Str; llvm::raw_string_ostream OS(Str); - dumpNode(OS, this, SM, /*IndentMask=*/{}); + dumpNode(OS, this, TM, /*IndentMask=*/{}); return std::move(OS.str()); } -std::string syntax::Node::dumpTokens(const SourceManager &SM) const { +std::string syntax::Node::dumpTokens(const TokenManager &TM) const { std::string Storage; llvm::raw_string_ostream OS(Storage); traverse(this, [&](const syntax::Node *N) { if (const auto *L = dyn_cast<syntax::Leaf>(N)) { - dumpLeaf(OS, L, SM); + OS << TM.getText(L->getTokenKey()); OS << " "; } }); @@ -297,7 +266,8 @@ void syntax::Node::assertInvariants() const { C.getRole() == NodeRole::ListDelimiter); if (C.getRole() == NodeRole::ListDelimiter) { assert(isa<Leaf>(C)); - assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind()); + // FIXME: re-enable it when there is way to retrieve token kind in Leaf. + // assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind()); } } |