Merge llvm-project main llvmorg-15-init-17485-ga3e38b4a206b
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvmorg-15-init-17485-ga3e38b4a206b. PR: 265425 MFC after: 2 weeks
This commit is contained in:
commit
fcaf7f8644
@ -77,7 +77,7 @@ class CommonEntityInfo {
|
||||
|
||||
void setSwiftPrivate(llvm::Optional<bool> Private) {
|
||||
SwiftPrivateSpecified = Private.has_value();
|
||||
SwiftPrivate = Private ? *Private : 0;
|
||||
SwiftPrivate = Private.value_or(0);
|
||||
}
|
||||
|
||||
friend bool operator==(const CommonEntityInfo &, const CommonEntityInfo &);
|
||||
|
@ -473,6 +473,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
};
|
||||
llvm::DenseMap<Module*, PerModuleInitializers*> ModuleInitializers;
|
||||
|
||||
/// For module code-gen cases, this is the top-level module we are building.
|
||||
Module *TopLevelModule = nullptr;
|
||||
|
||||
static constexpr unsigned ConstantArrayTypesLog2InitSize = 8;
|
||||
static constexpr unsigned GeneralTypesLog2InitSize = 9;
|
||||
static constexpr unsigned FunctionProtoTypesLog2InitSize = 12;
|
||||
@ -1076,6 +1079,12 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// Get the initializations to perform when importing a module, if any.
|
||||
ArrayRef<Decl*> getModuleInitializers(Module *M);
|
||||
|
||||
/// Set the (C++20) module we are building.
|
||||
void setModuleForCodeGen(Module *M) { TopLevelModule = M; }
|
||||
|
||||
/// Get module under construction, nullptr if this is not a C++20 module.
|
||||
Module *getModuleForCodeGen() const { return TopLevelModule; }
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const {
|
||||
return TUDecl->getMostRecentDecl();
|
||||
}
|
||||
|
@ -1887,7 +1887,10 @@ class FunctionDecl : public DeclaratorDecl,
|
||||
TK_FunctionTemplateSpecialization,
|
||||
// A function template specialization that hasn't yet been resolved to a
|
||||
// particular specialized function template.
|
||||
TK_DependentFunctionTemplateSpecialization
|
||||
TK_DependentFunctionTemplateSpecialization,
|
||||
// A non-template function which is in a dependent scope.
|
||||
TK_DependentNonTemplate
|
||||
|
||||
};
|
||||
|
||||
/// Stashed information about a defaulted function definition whose body has
|
||||
@ -1936,20 +1939,21 @@ class FunctionDecl : public DeclaratorDecl,
|
||||
/// The template or declaration that this declaration
|
||||
/// describes or was instantiated from, respectively.
|
||||
///
|
||||
/// For non-templates, this value will be NULL. For function
|
||||
/// declarations that describe a function template, this will be a
|
||||
/// pointer to a FunctionTemplateDecl. For member functions
|
||||
/// of class template specializations, this will be a MemberSpecializationInfo
|
||||
/// For non-templates this value will be NULL, unless this declaration was
|
||||
/// declared directly inside of a function template, in which case it will
|
||||
/// have a pointer to a FunctionDecl, stored in the NamedDecl. For function
|
||||
/// declarations that describe a function template, this will be a pointer to
|
||||
/// a FunctionTemplateDecl, stored in the NamedDecl. For member functions of
|
||||
/// class template specializations, this will be a MemberSpecializationInfo
|
||||
/// pointer containing information about the specialization.
|
||||
/// For function template specializations, this will be a
|
||||
/// FunctionTemplateSpecializationInfo, which contains information about
|
||||
/// the template being specialized and the template arguments involved in
|
||||
/// that specialization.
|
||||
llvm::PointerUnion<FunctionTemplateDecl *,
|
||||
MemberSpecializationInfo *,
|
||||
llvm::PointerUnion<NamedDecl *, MemberSpecializationInfo *,
|
||||
FunctionTemplateSpecializationInfo *,
|
||||
DependentFunctionTemplateSpecializationInfo *>
|
||||
TemplateOrSpecialization;
|
||||
TemplateOrSpecialization;
|
||||
|
||||
/// Provides source/type location info for the declaration name embedded in
|
||||
/// the DeclaratorDecl base class.
|
||||
@ -2692,6 +2696,13 @@ class FunctionDecl : public DeclaratorDecl,
|
||||
setInstantiationOfMemberFunction(getASTContext(), FD, TSK);
|
||||
}
|
||||
|
||||
/// Specify that this function declaration was instantiated from a
|
||||
/// FunctionDecl FD. This is only used if this is a function declaration
|
||||
/// declared locally inside of a function template.
|
||||
void setInstantiatedFromDecl(FunctionDecl *FD);
|
||||
|
||||
FunctionDecl *getInstantiatedFromDecl() const;
|
||||
|
||||
/// Retrieves the function template that is described by this
|
||||
/// function declaration.
|
||||
///
|
||||
|
@ -920,10 +920,12 @@ class alignas(8) Decl {
|
||||
|
||||
/// If this decl is defined inside a function/method/block it returns
|
||||
/// the corresponding DeclContext, otherwise it returns null.
|
||||
const DeclContext *getParentFunctionOrMethod() const;
|
||||
DeclContext *getParentFunctionOrMethod() {
|
||||
return const_cast<DeclContext*>(
|
||||
const_cast<const Decl*>(this)->getParentFunctionOrMethod());
|
||||
const DeclContext *
|
||||
getParentFunctionOrMethod(bool LexicalParent = false) const;
|
||||
DeclContext *getParentFunctionOrMethod(bool LexicalParent = false) {
|
||||
return const_cast<DeclContext *>(
|
||||
const_cast<const Decl *>(this)->getParentFunctionOrMethod(
|
||||
LexicalParent));
|
||||
}
|
||||
|
||||
/// Retrieves the "canonical" declaration of the given declaration.
|
||||
|
@ -3838,8 +3838,9 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
|
||||
InnerMatcher.matches(*ExprNode, Finder, Builder));
|
||||
}
|
||||
|
||||
/// Matches if the call expression's callee's declaration matches the
|
||||
/// given matcher.
|
||||
/// Matches 1) if the call expression's callee's declaration matches the
|
||||
/// given matcher; or 2) if the Obj-C message expression's callee's method
|
||||
/// declaration matches the given matcher.
|
||||
///
|
||||
/// Example matches y.x() (matcher = callExpr(callee(
|
||||
/// cxxMethodDecl(hasName("x")))))
|
||||
@ -3847,9 +3848,31 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
|
||||
/// class Y { public: void x(); };
|
||||
/// void z() { Y y; y.x(); }
|
||||
/// \endcode
|
||||
AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
|
||||
1) {
|
||||
return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
|
||||
///
|
||||
/// Example 2. Matches [I foo] with
|
||||
/// objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
|
||||
///
|
||||
/// \code
|
||||
/// @interface I: NSObject
|
||||
/// +(void)foo;
|
||||
/// @end
|
||||
/// ...
|
||||
/// [I foo]
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
|
||||
callee, AST_POLYMORPHIC_SUPPORTED_TYPES(ObjCMessageExpr, CallExpr),
|
||||
internal::Matcher<Decl>, InnerMatcher, 1) {
|
||||
if (const auto *CallNode = dyn_cast<CallExpr>(&Node))
|
||||
return callExpr(hasDeclaration(InnerMatcher))
|
||||
.matches(Node, Finder, Builder);
|
||||
else {
|
||||
// The dynamic cast below is guaranteed to succeed as there are only 2
|
||||
// supported return types.
|
||||
const auto *MsgNode = cast<ObjCMessageExpr>(&Node);
|
||||
const Decl *DeclNode = MsgNode->getMethodDecl();
|
||||
return (DeclNode != nullptr &&
|
||||
InnerMatcher.matches(*DeclNode, Finder, Builder));
|
||||
}
|
||||
}
|
||||
|
||||
/// Matches if the expression's or declaration's type matches a type
|
||||
|
@ -75,7 +75,7 @@ namespace til {
|
||||
class BasicBlock;
|
||||
|
||||
/// Enum for the different distinct classes of SExpr
|
||||
enum TIL_Opcode {
|
||||
enum TIL_Opcode : unsigned char {
|
||||
#define TIL_OPCODE_DEF(X) COP_##X,
|
||||
#include "ThreadSafetyOps.def"
|
||||
#undef TIL_OPCODE_DEF
|
||||
@ -278,7 +278,7 @@ class SExpr {
|
||||
public:
|
||||
SExpr() = delete;
|
||||
|
||||
TIL_Opcode opcode() const { return static_cast<TIL_Opcode>(Opcode); }
|
||||
TIL_Opcode opcode() const { return Opcode; }
|
||||
|
||||
// Subclasses of SExpr must define the following:
|
||||
//
|
||||
@ -321,7 +321,7 @@ class SExpr {
|
||||
SExpr(TIL_Opcode Op) : Opcode(Op) {}
|
||||
SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {}
|
||||
|
||||
const unsigned char Opcode;
|
||||
const TIL_Opcode Opcode;
|
||||
unsigned char Reserved = 0;
|
||||
unsigned short Flags = 0;
|
||||
unsigned SExprID = 0;
|
||||
@ -332,7 +332,7 @@ class SExpr {
|
||||
namespace ThreadSafetyTIL {
|
||||
|
||||
inline bool isTrivial(const SExpr *E) {
|
||||
unsigned Op = E->opcode();
|
||||
TIL_Opcode Op = E->opcode();
|
||||
return Op == COP_Variable || Op == COP_Literal || Op == COP_LiteralPtr;
|
||||
}
|
||||
|
||||
|
@ -63,9 +63,15 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis {
|
||||
using Lattice = LatticeT;
|
||||
|
||||
explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {}
|
||||
|
||||
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
|
||||
explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer)
|
||||
: TypeErasedDataflowAnalysis(ApplyBuiltinTransfer), Context(Context) {}
|
||||
|
||||
explicit DataflowAnalysis(ASTContext &Context,
|
||||
DataflowAnalysisOptions Options)
|
||||
: TypeErasedDataflowAnalysis(Options), Context(Context) {}
|
||||
|
||||
ASTContext &getASTContext() final { return Context; }
|
||||
|
||||
TypeErasedLattice typeErasedInitialElement() final {
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
@ -251,6 +252,8 @@ class DataflowAnalysisContext {
|
||||
/// `Val2` imposed by the flow condition.
|
||||
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
|
||||
|
||||
LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token);
|
||||
|
||||
private:
|
||||
struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> {
|
||||
static QualType getEmptyKey() {
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
@ -325,6 +324,8 @@ class Environment {
|
||||
/// imply that `Val` is true.
|
||||
bool flowConditionImplies(BoolValue &Val) const;
|
||||
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
|
||||
private:
|
||||
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
|
||||
/// return null.
|
||||
|
@ -23,6 +23,13 @@
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
/// Returns a string representation of a boolean assignment to true or false.
|
||||
std::string debugString(Solver::Result::Assignment Assignment);
|
||||
|
||||
/// Returns a string representation of the result status of a SAT check.
|
||||
std::string debugString(Solver::Result::Status Status);
|
||||
|
||||
/// Returns a string representation for the boolean value `B`.
|
||||
///
|
||||
/// Atomic booleans appearing in the boolean value `B` are assigned to labels
|
||||
@ -35,6 +42,20 @@ std::string debugString(
|
||||
const BoolValue &B,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
|
||||
/// Returns a string representation for `Constraints` - a collection of boolean
|
||||
/// formulas.
|
||||
///
|
||||
/// Atomic booleans appearing in the boolean value `Constraints` are assigned to
|
||||
/// labels either specified in `AtomNames` or created by default rules as B0,
|
||||
/// B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const llvm::DenseSet<BoolValue *> &Constraints,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
|
||||
/// Returns a string representation for `Constraints` - a collection of boolean
|
||||
/// formulas and the `Result` of satisfiability checking.
|
||||
///
|
||||
@ -46,7 +67,7 @@ std::string debugString(
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const std::vector<BoolValue *> &Constraints, const Solver::Result &Result,
|
||||
ArrayRef<BoolValue *> Constraints, const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
inline std::string debugString(
|
||||
const llvm::DenseSet<BoolValue *> &Constraints,
|
||||
|
@ -0,0 +1,47 @@
|
||||
//===-- NoopAnalysis.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a NoopAnalysis class that just uses the builtin transfer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H
|
||||
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
class NoopAnalysis : public DataflowAnalysis<NoopAnalysis, NoopLattice> {
|
||||
public:
|
||||
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
|
||||
NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer)
|
||||
: DataflowAnalysis<NoopAnalysis, NoopLattice>(Context,
|
||||
ApplyBuiltinTransfer) {}
|
||||
|
||||
/// `ApplyBuiltinTransfer` controls whether to run the built-in transfer
|
||||
/// functions that model memory during the analysis. Their results are not
|
||||
/// used by `NoopAnalysis`, but tests that need to inspect the environment
|
||||
/// should enable them.
|
||||
NoopAnalysis(ASTContext &Context, DataflowAnalysisOptions Options)
|
||||
: DataflowAnalysis<NoopAnalysis, NoopLattice>(Context, Options) {}
|
||||
|
||||
static NoopLattice initialElement() { return {}; }
|
||||
|
||||
void transfer(const Stmt *S, NoopLattice &E, Environment &Env) {}
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_NOOPANALYSIS_H
|
@ -30,6 +30,14 @@
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
struct DataflowAnalysisOptions {
|
||||
/// Determines whether to apply the built-in transfer functions.
|
||||
// FIXME: Remove this option once the framework supports composing analyses
|
||||
// (at which point the built-in transfer functions can be simply a standalone
|
||||
// analysis).
|
||||
bool ApplyBuiltinTransfer = true;
|
||||
};
|
||||
|
||||
/// Type-erased lattice element container.
|
||||
///
|
||||
/// Requirements:
|
||||
@ -42,16 +50,17 @@ struct TypeErasedLattice {
|
||||
|
||||
/// Type-erased base class for dataflow analyses built on a single lattice type.
|
||||
class TypeErasedDataflowAnalysis : public Environment::ValueModel {
|
||||
/// Determines whether to apply the built-in transfer functions.
|
||||
// FIXME: Remove this option once the framework supports composing analyses
|
||||
// (at which point the built-in transfer functions can be simply a standalone
|
||||
// analysis).
|
||||
bool ApplyBuiltinTransfer;
|
||||
DataflowAnalysisOptions Options;
|
||||
|
||||
public:
|
||||
TypeErasedDataflowAnalysis() : ApplyBuiltinTransfer(true) {}
|
||||
TypeErasedDataflowAnalysis() : Options({}) {}
|
||||
|
||||
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
|
||||
TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer)
|
||||
: ApplyBuiltinTransfer(ApplyBuiltinTransfer) {}
|
||||
: Options({ApplyBuiltinTransfer}) {}
|
||||
|
||||
TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options)
|
||||
: Options(Options) {}
|
||||
|
||||
virtual ~TypeErasedDataflowAnalysis() {}
|
||||
|
||||
@ -80,7 +89,7 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel {
|
||||
|
||||
/// Determines whether to apply the built-in transfer functions, which model
|
||||
/// the heap and stack in the `Environment`.
|
||||
bool applyBuiltinTransfer() const { return ApplyBuiltinTransfer; }
|
||||
bool applyBuiltinTransfer() const { return Options.ApplyBuiltinTransfer; }
|
||||
};
|
||||
|
||||
/// Type-erased model of the program at a given program point.
|
||||
|
@ -2703,7 +2703,7 @@ def Target : InheritableAttr {
|
||||
template<class Compare>
|
||||
ParsedTargetAttr parse(Compare cmp) const {
|
||||
ParsedTargetAttr Attrs = parse();
|
||||
llvm::sort(std::begin(Attrs.Features), std::end(Attrs.Features), cmp);
|
||||
llvm::sort(Attrs.Features, cmp);
|
||||
return Attrs;
|
||||
}
|
||||
|
||||
|
@ -339,12 +339,37 @@ TARGET_BUILTIN(__builtin_amdgcn_mfma_i32_16x16x32_i8, "V4iWiWiV4iIiIiIi", "nc",
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_i32_32x32x16_i8, "V16iWiWiV16iIiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_16x16x8_xf32, "V4fV2fV2fV4fIiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_32x32x4_xf32, "V16fV2fV2fV16fIiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_16x16x32_bf8_bf8, "V4fWiWiV4fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_16x16x32_bf8_fp8, "V4fWiWiV4fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_16x16x32_fp8_bf8, "V4fWiWiV4fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_16x16x32_fp8_fp8, "V4fWiWiV4fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_32x32x16_bf8_bf8, "V16fWiWiV16fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_32x32x16_bf8_fp8, "V16fWiWiV16fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_32x32x16_fp8_bf8, "V16fWiWiV16fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_mfma_f32_32x32x16_fp8_fp8, "V16fWiWiV16fIiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x32_f16, "V4fV4hV8hV4fiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x16_f16, "V16fV4hV8hV16fiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x32_bf16, "V4fV4sV8sV4fiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x16_bf16, "V16fV4sV8sV16fiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_i32_16x16x64_i8, "V4iV2iV4iV4iiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_i32_32x32x32_i8, "V16iV2iV4iV16iiIiIi", "nc", "mai-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x64_bf8_bf8, "V4fV2iV4iV4fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x64_bf8_fp8, "V4fV2iV4iV4fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x64_fp8_bf8, "V4fV2iV4iV4fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_16x16x64_fp8_fp8, "V4fV2iV4iV4fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x32_bf8_bf8, "V16fV2iV4iV16fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x32_bf8_fp8, "V16fV2iV4iV16fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x32_fp8_bf8, "V16fV2iV4iV16fiIiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x32_fp8_fp8, "V16fV2iV4iV16fiIiIi", "nc", "fp8-insts")
|
||||
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_f32_bf8, "fiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_f32_fp8, "fiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_f32_bf8, "V2fiIb", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_f32_fp8, "V2fiIb", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_bf8_f32, "iffiIb", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_pk_fp8_f32, "iffiIb", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf8_f32, "ifiiIi", "nc", "fp8-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_fp8_f32, "ifiiIi", "nc", "fp8-insts")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
@ -213,6 +213,10 @@ CODEGENOPT(AtomicProfileUpdate , 1, 0) ///< Set -fprofile-update=atomic
|
||||
ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNone)
|
||||
/// Choose profile kind for PGO use compilation.
|
||||
ENUM_CODEGENOPT(ProfileUse, ProfileInstrKind, 2, ProfileNone)
|
||||
/// Partition functions into N groups and select only functions in group i to be
|
||||
/// instrumented. Selected group numbers can be 0 to N-1 inclusive.
|
||||
VALUE_CODEGENOPT(ProfileTotalFunctionGroups, 32, 1)
|
||||
VALUE_CODEGENOPT(ProfileSelectedFunctionGroup, 32, 0)
|
||||
CODEGENOPT(CoverageMapping , 1, 0) ///< Generate coverage mapping regions to
|
||||
///< enable code coverage analysis.
|
||||
CODEGENOPT(DumpCoverageMapping , 1, 0) ///< Dump the generated coverage mapping
|
||||
|
@ -678,4 +678,11 @@ def err_drv_invalid_format_dxil_validator_version : Error<
|
||||
def err_drv_invalid_empty_dxil_validator_version : Error<
|
||||
"invalid validator version : %0\n"
|
||||
"If validator major version is 0, minor version must also be 0.">;
|
||||
|
||||
def warn_drv_sarif_format_unstable : Warning<
|
||||
"diagnostic formatting in SARIF mode is currently unstable">,
|
||||
InGroup<DiagGroup<"sarif-format-unstable">>;
|
||||
|
||||
def err_drv_riscv_unsupported_with_linker_relaxation : Error<
|
||||
"%0 is unsupported with RISC-V linker relaxation (-mrelax)">;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ def ArrayParameter : DiagGroup<"array-parameter">;
|
||||
def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">;
|
||||
def Availability : DiagGroup<"availability">;
|
||||
def Section : DiagGroup<"section">;
|
||||
def AutoImport : DiagGroup<"auto-import">;
|
||||
def : DiagGroup<"auto-import">;
|
||||
def FrameworkHdrQuotedInclude : DiagGroup<"quoted-include-in-framework-header">;
|
||||
def FrameworkIncludePrivateFromPublic :
|
||||
DiagGroup<"framework-include-private-from-public">;
|
||||
@ -490,6 +490,7 @@ def ModuleBuild : DiagGroup<"module-build">;
|
||||
def ModuleImport : DiagGroup<"module-import">;
|
||||
def ModuleConflict : DiagGroup<"module-conflict">;
|
||||
def ModuleFileExtension : DiagGroup<"module-file-extension">;
|
||||
def ModuleIncludeDirectiveTranslation : DiagGroup<"module-include-translation">;
|
||||
def RoundTripCC1Args : DiagGroup<"round-trip-cc1-args">;
|
||||
def NewlineEOF : DiagGroup<"newline-eof">;
|
||||
def Nullability : DiagGroup<"nullability">;
|
||||
|
@ -387,7 +387,15 @@ def ext_pp_include_search_ms : ExtWarn<
|
||||
def ext_pp_ident_directive : Extension<"#ident is a language extension">;
|
||||
def ext_pp_include_next_directive : Extension<
|
||||
"#include_next is a language extension">, InGroup<GNUIncludeNext>;
|
||||
def ext_pp_warning_directive : Extension<"#warning is a language extension">;
|
||||
|
||||
def ext_pp_warning_directive : Extension<
|
||||
"#warning is a %select{C2x|C++2b}0 extension">;
|
||||
def warn_cxx2b_compat_warning_directive : Warning<
|
||||
"#warning is incompatible with C++ standards before C++2b">,
|
||||
InGroup<CXXPre2bCompat>, DefaultIgnore;
|
||||
def warn_c2x_compat_warning_directive : Warning<
|
||||
"#warning is incompatible with C standards before C2x">,
|
||||
InGroup<CPre2xCompat>, DefaultIgnore;
|
||||
|
||||
def ext_pp_extra_tokens_at_eol : ExtWarn<
|
||||
"extra tokens at end of #%0 directive">, InGroup<ExtraTokens>;
|
||||
@ -851,9 +859,9 @@ def warn_framework_include_private_from_public : Warning<
|
||||
"public framework header includes private framework header '%0'"
|
||||
>, InGroup<FrameworkIncludePrivateFromPublic>;
|
||||
|
||||
def warn_auto_module_import : Warning<
|
||||
def remark_pp_include_directive_modular_translation : Remark<
|
||||
"treating #%select{include|import|include_next|__include_macros}0 as an "
|
||||
"import of module '%1'">, InGroup<AutoImport>, DefaultIgnore;
|
||||
"import of module '%1'">, InGroup<ModuleIncludeDirectiveTranslation>;
|
||||
def note_implicit_top_level_module_import_here : Note<
|
||||
"submodule of top-level module '%0' implicitly imported here">;
|
||||
def warn_uncovered_module_header : Warning<
|
||||
|
@ -74,7 +74,7 @@ class DiagnosticOptions : public RefCountedBase<DiagnosticOptions>{
|
||||
friend class CompilerInvocation;
|
||||
|
||||
public:
|
||||
enum TextDiagnosticFormat { Clang, MSVC, Vi };
|
||||
enum TextDiagnosticFormat { Clang, MSVC, Vi, SARIF };
|
||||
|
||||
// Default values.
|
||||
enum {
|
||||
|
@ -8037,24 +8037,6 @@ def err_incompatible_qualified_id : Error<
|
||||
"sending type to parameter of incompatible type}0,1"
|
||||
"|%diff{casting $ to incompatible type $|"
|
||||
"casting type to incompatible type}0,1}2">;
|
||||
def ext_typecheck_convert_pointer_int : ExtWarn<
|
||||
"incompatible pointer to integer conversion "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
"|%diff{passing $ to parameter of type $|"
|
||||
"passing to parameter of different type}0,1"
|
||||
"|%diff{returning $ from a function with result type $|"
|
||||
"returning from function with different return type}0,1"
|
||||
"|%diff{converting $ to type $|converting between types}0,1"
|
||||
"|%diff{initializing $ with an expression of type $|"
|
||||
"initializing with expression of different type}0,1"
|
||||
"|%diff{sending $ to parameter of type $|"
|
||||
"sending to parameter of different type}0,1"
|
||||
"|%diff{casting $ to type $|casting between types}0,1}2"
|
||||
"%select{|; dereference with *|"
|
||||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">,
|
||||
InGroup<IntConversion>;
|
||||
def err_typecheck_convert_pointer_int : Error<
|
||||
"incompatible pointer to integer conversion "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
@ -8072,24 +8054,9 @@ def err_typecheck_convert_pointer_int : Error<
|
||||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">;
|
||||
def ext_typecheck_convert_int_pointer : ExtWarn<
|
||||
"incompatible integer to pointer conversion "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
"|%diff{passing $ to parameter of type $|"
|
||||
"passing to parameter of different type}0,1"
|
||||
"|%diff{returning $ from a function with result type $|"
|
||||
"returning from function with different return type}0,1"
|
||||
"|%diff{converting $ to type $|converting between types}0,1"
|
||||
"|%diff{initializing $ with an expression of type $|"
|
||||
"initializing with expression of different type}0,1"
|
||||
"|%diff{sending $ to parameter of type $|"
|
||||
"sending to parameter of different type}0,1"
|
||||
"|%diff{casting $ to type $|casting between types}0,1}2"
|
||||
"%select{|; dereference with *|"
|
||||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">,
|
||||
InGroup<IntConversion>, SFINAEFailure;
|
||||
def ext_typecheck_convert_pointer_int : ExtWarn<
|
||||
err_typecheck_convert_pointer_int.Text>,
|
||||
InGroup<IntConversion>, DefaultError;
|
||||
def err_typecheck_convert_int_pointer : Error<
|
||||
"incompatible integer to pointer conversion "
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
@ -8107,6 +8074,9 @@ def err_typecheck_convert_int_pointer : Error<
|
||||
"; take the address with &|"
|
||||
"; remove *|"
|
||||
"; remove &}3">;
|
||||
def ext_typecheck_convert_int_pointer : ExtWarn<
|
||||
err_typecheck_convert_int_pointer.Text>,
|
||||
InGroup<IntConversion>, DefaultError;
|
||||
def ext_typecheck_convert_pointer_void_func : Extension<
|
||||
"%select{%diff{assigning to $ from $|assigning to different types}0,1"
|
||||
"|%diff{passing $ to parameter of type $|"
|
||||
|
@ -179,7 +179,6 @@ FEATURE(cxx_thread_local,
|
||||
FEATURE(cxx_trailing_return, LangOpts.CPlusPlus11)
|
||||
FEATURE(cxx_unicode_literals, LangOpts.CPlusPlus11)
|
||||
FEATURE(cxx_unrestricted_unions, LangOpts.CPlusPlus11)
|
||||
FEATURE(cxx_unstable, LangOpts.Unstable)
|
||||
FEATURE(cxx_user_literals, LangOpts.CPlusPlus11)
|
||||
FEATURE(cxx_variadic_templates, LangOpts.CPlusPlus11)
|
||||
// C++14 features
|
||||
@ -235,6 +234,7 @@ FEATURE(shadow_call_stack,
|
||||
LangOpts.Sanitize.has(SanitizerKind::ShadowCallStack))
|
||||
FEATURE(tls, PP.getTargetInfo().isTLSSupported())
|
||||
FEATURE(underlying_type, LangOpts.CPlusPlus)
|
||||
FEATURE(experimental_library, LangOpts.ExperimentalLibrary)
|
||||
|
||||
// C11 features supported by other languages as extensions.
|
||||
EXTENSION(c_alignas, true)
|
||||
|
@ -155,7 +155,7 @@ LANGOPT(GNUAsm , 1, 1, "GNU-style inline assembly")
|
||||
LANGOPT(Coroutines , 1, 0, "C++20 coroutines")
|
||||
LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods")
|
||||
LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments")
|
||||
LANGOPT(Unstable , 1, 0, "Enable unstable and experimental features")
|
||||
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")
|
||||
|
||||
LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
|
||||
|
||||
@ -424,6 +424,7 @@ LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0,
|
||||
LANGOPT(RegisterStaticDestructors, 1, 1, "Register C++ static destructors")
|
||||
|
||||
LANGOPT(MatrixTypes, 1, 0, "Enable or disable the builtin matrix type")
|
||||
LANGOPT(StrictFlexArrays, 2, 0, "Rely on strict definition of flexible arrays")
|
||||
|
||||
COMPATIBLE_VALUE_LANGOPT(MaxTokens, 32, 0, "Max number of tokens per TU or 0")
|
||||
|
||||
|
@ -665,6 +665,18 @@ class Module {
|
||||
Module *findSubmodule(StringRef Name) const;
|
||||
Module *findOrInferSubmodule(StringRef Name);
|
||||
|
||||
/// Get the Global Module Fragment (sub-module) for this module, it there is
|
||||
/// one.
|
||||
///
|
||||
/// \returns The GMF sub-module if found, or NULL otherwise.
|
||||
Module *getGlobalModuleFragment() { return findSubmodule("<global>"); }
|
||||
|
||||
/// Get the Private Module Fragment (sub-module) for this module, it there is
|
||||
/// one.
|
||||
///
|
||||
/// \returns The PMF sub-module if found, or NULL otherwise.
|
||||
Module *getPrivateModuleFragment() { return findSubmodule("<private>"); }
|
||||
|
||||
/// Determine whether the specified module would be visible to
|
||||
/// a lookup at the end of this module.
|
||||
///
|
||||
|
@ -41,6 +41,8 @@ class NoSanitizeList {
|
||||
bool containsFunction(SanitizerMask Mask, StringRef FunctionName) const;
|
||||
bool containsFile(SanitizerMask Mask, StringRef FileName,
|
||||
StringRef Category = StringRef()) const;
|
||||
bool containsMainFile(SanitizerMask Mask, StringRef FileName,
|
||||
StringRef Category = StringRef()) const;
|
||||
bool containsLocation(SanitizerMask Mask, SourceLocation Loc,
|
||||
StringRef Category = StringRef()) const;
|
||||
};
|
||||
|
440
contrib/llvm-project/clang/include/clang/Basic/Sarif.h
Normal file
440
contrib/llvm-project/clang/include/clang/Basic/Sarif.h
Normal file
@ -0,0 +1,440 @@
|
||||
//== clang/Basic/Sarif.h - SARIF Diagnostics Object Model -------*- C++ -*--==//
|
||||
//
|
||||
// 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
|
||||
/// Defines clang::SarifDocumentWriter, clang::SarifRule, clang::SarifResult.
|
||||
///
|
||||
/// The document built can be accessed as a JSON Object.
|
||||
/// Several value semantic types are also introduced which represent properties
|
||||
/// of the SARIF standard, such as 'artifact', 'result', 'rule'.
|
||||
///
|
||||
/// A SARIF (Static Analysis Results Interchange Format) document is JSON
|
||||
/// document that describes in detail the results of running static analysis
|
||||
/// tools on a project. Each (non-trivial) document consists of at least one
|
||||
/// "run", which are themselves composed of details such as:
|
||||
/// * Tool: The tool that was run
|
||||
/// * Rules: The rules applied during the tool run, represented by
|
||||
/// \c reportingDescriptor objects in SARIF
|
||||
/// * Results: The matches for the rules applied against the project(s) being
|
||||
/// evaluated, represented by \c result objects in SARIF
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html">The SARIF standard</a>
|
||||
/// 2. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836">SARIF<pre>reportingDescriptor</pre></a>
|
||||
/// 3. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638">SARIF<pre>result</pre></a>
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_SARIF_H
|
||||
#define LLVM_CLANG_BASIC_SARIF_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/JSON.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
||||
class SarifDocumentWriter;
|
||||
class SourceManager;
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// \internal
|
||||
/// An artifact location is SARIF's way of describing the complete location
|
||||
/// of an artifact encountered during analysis. The \c artifactLocation object
|
||||
/// typically consists of a URI, and/or an index to reference the artifact it
|
||||
/// locates.
|
||||
///
|
||||
/// This builder makes an additional assumption: that every artifact encountered
|
||||
/// by \c clang will be a physical, top-level artifact. Which is why the static
|
||||
/// creation method \ref SarifArtifactLocation::create takes a mandatory URI
|
||||
/// parameter. The official standard states that either a \c URI or \c Index
|
||||
/// must be available in the object, \c clang picks the \c URI as a reasonable
|
||||
/// default, because it intends to deal in physical artifacts for now.
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317427">artifactLocation object</a>
|
||||
/// 2. \ref SarifArtifact
|
||||
class SarifArtifactLocation {
|
||||
private:
|
||||
friend class clang::SarifDocumentWriter;
|
||||
|
||||
llvm::Optional<uint32_t> Index;
|
||||
std::string URI;
|
||||
|
||||
SarifArtifactLocation() = delete;
|
||||
explicit SarifArtifactLocation(const std::string &URI) : URI(URI) {}
|
||||
|
||||
public:
|
||||
static SarifArtifactLocation create(llvm::StringRef URI) {
|
||||
return SarifArtifactLocation{URI.str()};
|
||||
}
|
||||
|
||||
SarifArtifactLocation setIndex(uint32_t Idx) {
|
||||
Index = Idx;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// \internal
|
||||
/// An artifact in SARIF is any object (a sequence of bytes) addressable by
|
||||
/// a URI (RFC 3986). The most common type of artifact for clang's use-case
|
||||
/// would be source files. SARIF's artifact object is described in detail in
|
||||
/// section 3.24.
|
||||
//
|
||||
/// Since every clang artifact MUST have a location (there being no nested
|
||||
/// artifacts), the creation method \ref SarifArtifact::create requires a
|
||||
/// \ref SarifArtifactLocation object.
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317611">artifact object</a>
|
||||
class SarifArtifact {
|
||||
private:
|
||||
friend class clang::SarifDocumentWriter;
|
||||
|
||||
llvm::Optional<uint32_t> Offset;
|
||||
llvm::Optional<size_t> Length;
|
||||
std::string MimeType;
|
||||
SarifArtifactLocation Location;
|
||||
llvm::SmallVector<std::string, 4> Roles;
|
||||
|
||||
SarifArtifact() = delete;
|
||||
|
||||
explicit SarifArtifact(const SarifArtifactLocation &Loc) : Location(Loc) {}
|
||||
|
||||
public:
|
||||
static SarifArtifact create(const SarifArtifactLocation &Loc) {
|
||||
return SarifArtifact{Loc};
|
||||
}
|
||||
|
||||
SarifArtifact setOffset(uint32_t ArtifactOffset) {
|
||||
Offset = ArtifactOffset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifArtifact setLength(size_t NumBytes) {
|
||||
Length = NumBytes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifArtifact setRoles(std::initializer_list<llvm::StringRef> ArtifactRoles) {
|
||||
Roles.assign(ArtifactRoles.begin(), ArtifactRoles.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifArtifact setMimeType(llvm::StringRef ArtifactMimeType) {
|
||||
MimeType = ArtifactMimeType.str();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
enum class ThreadFlowImportance { Important, Essential, Unimportant };
|
||||
|
||||
/// A thread flow is a sequence of code locations that specify a possible path
|
||||
/// through a single thread of execution.
|
||||
/// A thread flow in SARIF is related to a code flow which describes
|
||||
/// the progress of one or more programs through one or more thread flows.
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317744">threadFlow object</a>
|
||||
/// 2. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317740">codeFlow object</a>
|
||||
class ThreadFlow {
|
||||
friend class SarifDocumentWriter;
|
||||
|
||||
CharSourceRange Range;
|
||||
ThreadFlowImportance Importance;
|
||||
std::string Message;
|
||||
|
||||
ThreadFlow() = default;
|
||||
|
||||
public:
|
||||
static ThreadFlow create() { return {}; }
|
||||
|
||||
ThreadFlow setRange(const CharSourceRange &ItemRange) {
|
||||
assert(ItemRange.isCharRange() &&
|
||||
"ThreadFlows require a character granular source range!");
|
||||
Range = ItemRange;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ThreadFlow setImportance(const ThreadFlowImportance &ItemImportance) {
|
||||
Importance = ItemImportance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ThreadFlow setMessage(llvm::StringRef ItemMessage) {
|
||||
Message = ItemMessage.str();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// A SARIF rule (\c reportingDescriptor object) contains information that
|
||||
/// describes a reporting item generated by a tool. A reporting item is
|
||||
/// either a result of analysis or notification of a condition encountered by
|
||||
/// the tool. Rules are arbitrary but are identifiable by a hierarchical
|
||||
/// rule-id.
|
||||
///
|
||||
/// This builder provides an interface to create SARIF \c reportingDescriptor
|
||||
/// objects via the \ref SarifRule::create static method.
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317836">reportingDescriptor object</a>
|
||||
class SarifRule {
|
||||
friend class clang::SarifDocumentWriter;
|
||||
|
||||
std::string Name;
|
||||
std::string Id;
|
||||
std::string Description;
|
||||
std::string HelpURI;
|
||||
|
||||
SarifRule() = default;
|
||||
|
||||
public:
|
||||
static SarifRule create() { return {}; }
|
||||
|
||||
SarifRule setName(llvm::StringRef RuleName) {
|
||||
Name = RuleName.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifRule setRuleId(llvm::StringRef RuleId) {
|
||||
Id = RuleId.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifRule setDescription(llvm::StringRef RuleDesc) {
|
||||
Description = RuleDesc.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifRule setHelpURI(llvm::StringRef RuleHelpURI) {
|
||||
HelpURI = RuleHelpURI.str();
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// A SARIF result (also called a "reporting item") is a unit of output
|
||||
/// produced when one of the tool's \c reportingDescriptor encounters a match
|
||||
/// on the file being analysed by the tool.
|
||||
///
|
||||
/// This builder provides a \ref SarifResult::create static method that can be
|
||||
/// used to create an empty shell onto which attributes can be added using the
|
||||
/// \c setX(...) methods.
|
||||
///
|
||||
/// For example:
|
||||
/// \code{.cpp}
|
||||
/// SarifResult result = SarifResult::create(...)
|
||||
/// .setRuleId(...)
|
||||
/// .setDiagnosticMessage(...);
|
||||
/// \endcode
|
||||
///
|
||||
/// Reference:
|
||||
/// 1. <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317638">SARIF<pre>result</pre></a>
|
||||
class SarifResult {
|
||||
friend class clang::SarifDocumentWriter;
|
||||
|
||||
// NOTE:
|
||||
// This type cannot fit all possible indexes representable by JSON, but is
|
||||
// chosen because it is the largest unsigned type that can be safely
|
||||
// converted to an \c int64_t.
|
||||
uint32_t RuleIdx;
|
||||
std::string RuleId;
|
||||
std::string DiagnosticMessage;
|
||||
llvm::SmallVector<CharSourceRange, 8> Locations;
|
||||
llvm::SmallVector<ThreadFlow, 8> ThreadFlows;
|
||||
|
||||
SarifResult() = delete;
|
||||
explicit SarifResult(uint32_t RuleIdx) : RuleIdx(RuleIdx) {}
|
||||
|
||||
public:
|
||||
static SarifResult create(uint32_t RuleIdx) { return SarifResult{RuleIdx}; }
|
||||
|
||||
SarifResult setIndex(uint32_t Idx) {
|
||||
RuleIdx = Idx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult setRuleId(llvm::StringRef Id) {
|
||||
RuleId = Id.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult setDiagnosticMessage(llvm::StringRef Message) {
|
||||
DiagnosticMessage = Message.str();
|
||||
return *this;
|
||||
}
|
||||
|
||||
SarifResult setLocations(llvm::ArrayRef<CharSourceRange> DiagLocs) {
|
||||
#ifndef NDEBUG
|
||||
for (const auto &Loc : DiagLocs) {
|
||||
assert(Loc.isCharRange() &&
|
||||
"SARIF Results require character granular source ranges!");
|
||||
}
|
||||
#endif
|
||||
Locations.assign(DiagLocs.begin(), DiagLocs.end());
|
||||
return *this;
|
||||
}
|
||||
SarifResult setThreadFlows(llvm::ArrayRef<ThreadFlow> ThreadFlowResults) {
|
||||
ThreadFlows.assign(ThreadFlowResults.begin(), ThreadFlowResults.end());
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/// This class handles creating a valid SARIF document given various input
|
||||
/// attributes. However, it requires an ordering among certain method calls:
|
||||
///
|
||||
/// 1. Because every SARIF document must contain at least 1 \c run, callers
|
||||
/// must ensure that \ref SarifDocumentWriter::createRun is is called before
|
||||
/// any other methods.
|
||||
/// 2. If SarifDocumentWriter::endRun is called, callers MUST call
|
||||
/// SarifDocumentWriter::createRun, before invoking any of the result
|
||||
/// aggregation methods such as SarifDocumentWriter::appendResult etc.
|
||||
class SarifDocumentWriter {
|
||||
private:
|
||||
const llvm::StringRef SchemaURI{
|
||||
"https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/"
|
||||
"sarif-schema-2.1.0.json"};
|
||||
const llvm::StringRef SchemaVersion{"2.1.0"};
|
||||
|
||||
/// \internal
|
||||
/// Return a pointer to the current tool. Asserts that a run exists.
|
||||
llvm::json::Object &getCurrentTool();
|
||||
|
||||
/// \internal
|
||||
/// Checks if there is a run associated with this document.
|
||||
///
|
||||
/// \return true on success
|
||||
bool hasRun() const;
|
||||
|
||||
/// \internal
|
||||
/// Reset portions of the internal state so that the document is ready to
|
||||
/// receive data for a new run.
|
||||
void reset();
|
||||
|
||||
/// \internal
|
||||
/// Return a mutable reference to the current run, after asserting it exists.
|
||||
///
|
||||
/// \note It is undefined behavior to call this if a run does not exist in
|
||||
/// the SARIF document.
|
||||
llvm::json::Object &getCurrentRun();
|
||||
|
||||
/// Create a code flow object for the given threadflows.
|
||||
/// See \ref ThreadFlow.
|
||||
///
|
||||
/// \note It is undefined behavior to call this if a run does not exist in
|
||||
/// the SARIF document.
|
||||
llvm::json::Object
|
||||
createCodeFlow(const llvm::ArrayRef<ThreadFlow> ThreadFlows);
|
||||
|
||||
/// Add the given threadflows to the ones this SARIF document knows about.
|
||||
llvm::json::Array
|
||||
createThreadFlows(const llvm::ArrayRef<ThreadFlow> ThreadFlows);
|
||||
|
||||
/// Add the given \ref CharSourceRange to the SARIF document as a physical
|
||||
/// location, with its corresponding artifact.
|
||||
llvm::json::Object createPhysicalLocation(const CharSourceRange &R);
|
||||
|
||||
public:
|
||||
SarifDocumentWriter() = delete;
|
||||
|
||||
/// Create a new empty SARIF document with the given source manager.
|
||||
SarifDocumentWriter(const SourceManager &SourceMgr) : SourceMgr(SourceMgr) {}
|
||||
|
||||
/// Release resources held by this SARIF document.
|
||||
~SarifDocumentWriter() = default;
|
||||
|
||||
/// Create a new run with which any upcoming analysis will be associated.
|
||||
/// Each run requires specifying the tool that is generating reporting items.
|
||||
void createRun(const llvm::StringRef ShortToolName,
|
||||
const llvm::StringRef LongToolName,
|
||||
const llvm::StringRef ToolVersion = CLANG_VERSION_STRING);
|
||||
|
||||
/// If there is a current run, end it.
|
||||
///
|
||||
/// This method collects various book-keeping required to clear and close
|
||||
/// resources associated with the current run, but may also allocate some
|
||||
/// for the next run.
|
||||
///
|
||||
/// Calling \ref endRun before associating a run through \ref createRun leads
|
||||
/// to undefined behaviour.
|
||||
void endRun();
|
||||
|
||||
/// Associate the given rule with the current run.
|
||||
///
|
||||
/// Returns an integer rule index for the created rule that is unique within
|
||||
/// the current run, which can then be used to create a \ref SarifResult
|
||||
/// to add to the current run. Note that a rule must exist before being
|
||||
/// referenced by a result.
|
||||
///
|
||||
/// \pre
|
||||
/// There must be a run associated with the document, failing to do so will
|
||||
/// cause undefined behaviour.
|
||||
size_t createRule(const SarifRule &Rule);
|
||||
|
||||
/// Append a new result to the currently in-flight run.
|
||||
///
|
||||
/// \pre
|
||||
/// There must be a run associated with the document, failing to do so will
|
||||
/// cause undefined behaviour.
|
||||
/// \pre
|
||||
/// \c RuleIdx used to create the result must correspond to a rule known by
|
||||
/// the SARIF document. It must be the value returned by a previous call
|
||||
/// to \ref createRule.
|
||||
void appendResult(const SarifResult &SarifResult);
|
||||
|
||||
/// Return the SARIF document in its current state.
|
||||
/// Calling this will trigger a copy of the internal state including all
|
||||
/// reported diagnostics, resulting in an expensive call.
|
||||
llvm::json::Object createDocument();
|
||||
|
||||
private:
|
||||
/// Source Manager to use for the current SARIF document.
|
||||
const SourceManager &SourceMgr;
|
||||
|
||||
/// Flag to track the state of this document:
|
||||
/// A closed document is one on which a new runs must be created.
|
||||
/// This could be a document that is freshly created, or has recently
|
||||
/// finished writing to a previous run.
|
||||
bool Closed = true;
|
||||
|
||||
/// A sequence of SARIF runs.
|
||||
/// Each run object describes a single run of an analysis tool and contains
|
||||
/// the output of that run.
|
||||
///
|
||||
/// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317484">run object</a>
|
||||
llvm::json::Array Runs;
|
||||
|
||||
/// The list of rules associated with the most recent active run. These are
|
||||
/// defined using the diagnostics passed to the SarifDocument. Each rule
|
||||
/// need not be unique through the result set. E.g. there may be several
|
||||
/// 'syntax' errors throughout code under analysis, each of which has its
|
||||
/// own specific diagnostic message (and consequently, RuleId). Rules are
|
||||
/// also known as "reportingDescriptor" objects in SARIF.
|
||||
///
|
||||
/// Reference: <a href="https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317556">rules property</a>
|
||||
llvm::SmallVector<SarifRule, 32> CurrentRules;
|
||||
|
||||
/// The list of artifacts that have been encountered on the most recent active
|
||||
/// run. An artifact is defined in SARIF as a sequence of bytes addressable
|
||||
/// by a URI. A common example for clang's case would be files named by
|
||||
/// filesystem paths.
|
||||
llvm::StringMap<detail::SarifArtifact> CurrentArtifacts;
|
||||
};
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_SARIF_H
|
@ -36,7 +36,8 @@ enum ClangFlags {
|
||||
FC1Option = (1 << 15),
|
||||
FlangOnlyOption = (1 << 16),
|
||||
DXCOption = (1 << 17),
|
||||
Ignored = (1 << 18),
|
||||
CLDXCOption = (1 << 18),
|
||||
Ignored = (1 << 19),
|
||||
};
|
||||
|
||||
enum ID {
|
||||
|
@ -53,6 +53,10 @@ def CC1AsOption : OptionFlag;
|
||||
// are made available when the driver is running in DXC compatibility mode.
|
||||
def DXCOption : OptionFlag;
|
||||
|
||||
// CLDXCOption - This is a cl.exe/dxc.exe compatibility option. Options with this flag
|
||||
// are made available when the driver is running in CL/DXC compatibility mode.
|
||||
def CLDXCOption : OptionFlag;
|
||||
|
||||
// NoDriverOption - This option should not be accepted by the driver.
|
||||
def NoDriverOption : OptionFlag;
|
||||
|
||||
@ -1140,6 +1144,12 @@ def fallow_unsupported : Flag<["-"], "fallow-unsupported">, Group<f_Group>;
|
||||
def fapple_kext : Flag<["-"], "fapple-kext">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use Apple's kernel extensions ABI">,
|
||||
MarshallingInfoFlag<LangOpts<"AppleKext">>;
|
||||
def fstrict_flex_arrays_EQ : Joined<["-"], "fstrict-flex-arrays=">,Group<f_Group>,
|
||||
MetaVarName<"<n>">, Values<"0,1,2">,
|
||||
LangOpts<"StrictFlexArrays">,
|
||||
Flags<[CC1Option]>,
|
||||
HelpText<"Enable optimizations based on the strict definition of flexible arrays">,
|
||||
MarshallingInfoInt<LangOpts<"StrictFlexArrays">>;
|
||||
defm apple_pragma_pack : BoolFOption<"apple-pragma-pack",
|
||||
LangOpts<"ApplePragmaPack">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option], "Enable Apple gcc-compatible #pragma pack handling">,
|
||||
@ -1183,9 +1193,13 @@ defm coroutines_ts : BoolFOption<"coroutines-ts",
|
||||
PosFlag<SetTrue, [CC1Option], "Enable support for the C++ Coroutines TS">,
|
||||
NegFlag<SetFalse>>;
|
||||
|
||||
defm unstable : BoolFOption<"unstable",
|
||||
LangOpts<"Unstable">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option, CoreOption], "Enable unstable and experimental features">,
|
||||
defm experimental_library : BoolFOption<"experimental-library",
|
||||
LangOpts<"ExperimentalLibrary">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option, CoreOption], "Control whether unstable and experimental library features are enabled. "
|
||||
"This option enables various library features that are either experimental (also known as TSes), or have been "
|
||||
"but are not stable yet in the selected Standard Library implementation. It is not recommended to use this option "
|
||||
"in production code, since neither ABI nor API stability are guaranteed. This is intended to provide a preview "
|
||||
"of features that will ship in the future for experimentation purposes">,
|
||||
NegFlag<SetFalse>>;
|
||||
|
||||
def fembed_offload_object_EQ : Joined<["-"], "fembed-offload-object=">,
|
||||
@ -1333,6 +1347,15 @@ def fprofile_list_EQ : Joined<["-"], "fprofile-list=">,
|
||||
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
|
||||
HelpText<"Filename defining the list of functions/files to instrument">,
|
||||
MarshallingInfoStringVector<LangOpts<"ProfileListFiles">>;
|
||||
def fprofile_function_groups : Joined<["-"], "fprofile-function-groups=">,
|
||||
Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<N>">,
|
||||
HelpText<"Partition functions into N groups and select only functions in group i to be instrumented using -fprofile-selected-function-group">,
|
||||
MarshallingInfoInt<CodeGenOpts<"ProfileTotalFunctionGroups">, "1">;
|
||||
def fprofile_selected_function_group :
|
||||
Joined<["-"], "fprofile-selected-function-group=">, Group<f_Group>,
|
||||
Flags<[CC1Option]>, MetaVarName<"<i>">,
|
||||
HelpText<"Partition functions into N groups using -fprofile-function-groups and select only functions in group i to be instrumented. The valid range is 0 to N-1 inclusive">,
|
||||
MarshallingInfoInt<CodeGenOpts<"ProfileSelectedFunctionGroup">>;
|
||||
def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">,
|
||||
Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>, MetaVarName<"<option>">,
|
||||
HelpText<"Control emission of Swift async extended frame info">,
|
||||
@ -2848,6 +2871,15 @@ def ftime_trace_granularity_EQ : Joined<["-"], "ftime-trace-granularity=">, Grou
|
||||
HelpText<"Minimum time granularity (in microseconds) traced by time profiler">,
|
||||
Flags<[CC1Option, CoreOption]>,
|
||||
MarshallingInfoInt<FrontendOpts<"TimeTraceGranularity">, "500u">;
|
||||
def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>,
|
||||
HelpText<"Turn on time profiler. Generates JSON file based on output filename. "
|
||||
"Specify the path which stores the tracing output file.">,
|
||||
DocBrief<[{
|
||||
Turn on time profiler. Generates JSON file based on output filename. Results
|
||||
can be analyzed with chrome://tracing or `Speedscope App
|
||||
<https://www.speedscope.app>`_ for flamegraph visualization.}]>,
|
||||
Flags<[CC1Option, CoreOption]>,
|
||||
MarshallingInfoString<FrontendOpts<"TimeTracePath">>;
|
||||
def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group<f_Group>,
|
||||
HelpText<"Print subprocess statistics">;
|
||||
def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group<f_Group>,
|
||||
@ -5556,8 +5588,8 @@ def diagnostic_serialized_file : Separate<["-"], "serialize-diagnostic-file">,
|
||||
|
||||
def fdiagnostics_format : Separate<["-"], "fdiagnostics-format">,
|
||||
HelpText<"Change diagnostic formatting to match IDE and command line tools">,
|
||||
Values<"clang,msvc,vi">,
|
||||
NormalizedValuesScope<"DiagnosticOptions">, NormalizedValues<["Clang", "MSVC", "Vi"]>,
|
||||
Values<"clang,msvc,vi,sarif,SARIF">,
|
||||
NormalizedValuesScope<"DiagnosticOptions">, NormalizedValues<["Clang", "MSVC", "Vi", "SARIF", "SARIF"]>,
|
||||
MarshallingInfoEnum<DiagnosticOpts<"Format">, "Clang">;
|
||||
def fdiagnostics_show_category : Separate<["-"], "fdiagnostics-show-category">,
|
||||
HelpText<"Print diagnostic category">,
|
||||
@ -6327,7 +6359,7 @@ def defsym : Separate<["-"], "defsym">,
|
||||
// clang-cl Options
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def cl_Group : OptionGroup<"<clang-cl options>">, Flags<[CLOption]>,
|
||||
def cl_Group : OptionGroup<"<clang-cl options>">, Flags<[CLDXCOption]>,
|
||||
HelpText<"CL.EXE COMPATIBILITY OPTIONS">;
|
||||
|
||||
def cl_compile_Group : OptionGroup<"<clang-cl compile-only options>">,
|
||||
@ -6357,6 +6389,9 @@ class CLIgnoredJoined<string name> : Option<["/", "-"], name, KIND_JOINED>,
|
||||
class CLJoinedOrSeparate<string name> : Option<["/", "-"], name,
|
||||
KIND_JOINED_OR_SEPARATE>, Group<cl_Group>, Flags<[CLOption, NoXarchOption]>;
|
||||
|
||||
class CLDXCJoinedOrSeparate<string name> : Option<["/", "-"], name,
|
||||
KIND_JOINED_OR_SEPARATE>, Group<cl_Group>, Flags<[CLDXCOption, NoXarchOption]>;
|
||||
|
||||
class CLCompileJoinedOrSeparate<string name> : Option<["/", "-"], name,
|
||||
KIND_JOINED_OR_SEPARATE>, Group<cl_compile_Group>,
|
||||
Flags<[CLOption, NoXarchOption]>;
|
||||
@ -6434,7 +6469,7 @@ def _SLASH_help : CLFlag<"help">, Alias<help>,
|
||||
def _SLASH_HELP : CLFlag<"HELP">, Alias<help>;
|
||||
def _SLASH_hotpatch : CLFlag<"hotpatch">, Alias<fms_hotpatch>,
|
||||
HelpText<"Create hotpatchable image">;
|
||||
def _SLASH_I : CLJoinedOrSeparate<"I">,
|
||||
def _SLASH_I : CLDXCJoinedOrSeparate<"I">,
|
||||
HelpText<"Add directory to include search path">, MetaVarName<"<dir>">,
|
||||
Alias<I>;
|
||||
def _SLASH_J : CLFlag<"J">, HelpText<"Make char type unsigned">,
|
||||
|
@ -786,7 +786,7 @@ struct FormatStyle {
|
||||
};
|
||||
|
||||
/// The template declaration breaking style to use.
|
||||
/// \version 7
|
||||
/// \version 3.4
|
||||
BreakTemplateDeclarationsStyle AlwaysBreakTemplateDeclarations;
|
||||
|
||||
/// A vector of strings that should be interpreted as attributes/qualifiers
|
||||
|
@ -499,6 +499,9 @@ class FrontendOptions {
|
||||
/// Minimum time granularity (in microseconds) traced by time profiler.
|
||||
unsigned TimeTraceGranularity;
|
||||
|
||||
/// Path which stores the output files for -ftime-trace
|
||||
std::string TimeTracePath;
|
||||
|
||||
public:
|
||||
FrontendOptions()
|
||||
: DisableFree(false), RelocatablePCH(false), ShowHelp(false),
|
||||
|
@ -1019,6 +1019,10 @@ class CodeCompleteConsumer {
|
||||
/// for which we only have a function prototype.
|
||||
CK_FunctionType,
|
||||
|
||||
/// The candidate is a variable or expression of function type
|
||||
/// for which we have the location of the prototype declaration.
|
||||
CK_FunctionProtoTypeLoc,
|
||||
|
||||
/// The candidate is a template, template arguments are being completed.
|
||||
CK_Template,
|
||||
|
||||
@ -1043,6 +1047,10 @@ class CodeCompleteConsumer {
|
||||
/// when Kind == CK_FunctionType.
|
||||
const FunctionType *Type;
|
||||
|
||||
/// The location of the function prototype that describes the entity being
|
||||
/// called, when Kind == CK_FunctionProtoTypeLoc.
|
||||
FunctionProtoTypeLoc ProtoTypeLoc;
|
||||
|
||||
/// The template overload candidate, available when
|
||||
/// Kind == CK_Template.
|
||||
const TemplateDecl *Template;
|
||||
@ -1068,6 +1076,11 @@ class CodeCompleteConsumer {
|
||||
assert(Type != nullptr);
|
||||
}
|
||||
|
||||
OverloadCandidate(FunctionProtoTypeLoc Prototype)
|
||||
: Kind(CK_FunctionProtoTypeLoc), ProtoTypeLoc(Prototype) {
|
||||
assert(!Prototype.isNull());
|
||||
}
|
||||
|
||||
OverloadCandidate(const RecordDecl *Aggregate)
|
||||
: Kind(CK_Aggregate), AggregateType(Aggregate) {
|
||||
assert(Aggregate != nullptr);
|
||||
@ -1093,6 +1106,11 @@ class CodeCompleteConsumer {
|
||||
/// function is stored.
|
||||
const FunctionType *getFunctionType() const;
|
||||
|
||||
/// Retrieve the function ProtoTypeLoc candidate.
|
||||
/// This can be called for any Kind, but returns null for kinds
|
||||
/// other than CK_FunctionProtoTypeLoc.
|
||||
const FunctionProtoTypeLoc getFunctionProtoTypeLoc() const;
|
||||
|
||||
const TemplateDecl *getTemplate() const {
|
||||
assert(getKind() == CK_Template && "Not a template");
|
||||
return Template;
|
||||
|
@ -2281,6 +2281,11 @@ class Sema final {
|
||||
return ModuleScopes.empty() ? nullptr : ModuleScopes.back().Module;
|
||||
}
|
||||
|
||||
/// Is the module scope we are an interface?
|
||||
bool currentModuleIsInterface() const {
|
||||
return ModuleScopes.empty() ? false : ModuleScopes.back().ModuleInterface;
|
||||
}
|
||||
|
||||
/// Get the module owning an entity.
|
||||
Module *getOwningModule(const Decl *Entity) {
|
||||
return Entity->getOwningModule();
|
||||
|
@ -119,6 +119,9 @@ class ConstraintManager {
|
||||
const char *NL, unsigned int Space,
|
||||
bool IsDot) const = 0;
|
||||
|
||||
virtual void printValue(raw_ostream &Out, ProgramStateRef State,
|
||||
SymbolRef Sym) {}
|
||||
|
||||
/// Convenience method to query the state to see if a symbol is null or
|
||||
/// not null, or if neither assumption can be made.
|
||||
ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
|
||||
|
@ -617,6 +617,11 @@ class ExprEngine {
|
||||
return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T);
|
||||
}
|
||||
|
||||
/// Retreives which element is being constructed in a non POD type array.
|
||||
static Optional<unsigned>
|
||||
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// By looking at a certain item that may be potentially part of an object's
|
||||
/// ConstructionContext, retrieve such object's location. A particular
|
||||
/// statement can be transparently passed as \p Item in most cases.
|
||||
@ -708,10 +713,19 @@ class ExprEngine {
|
||||
/// fully implemented it sometimes indicates that it failed via its
|
||||
/// out-parameter CallOpts; in such cases a fake temporary region is
|
||||
/// returned, which is better than nothing but does not represent
|
||||
/// the actual behavior of the program.
|
||||
SVal computeObjectUnderConstruction(
|
||||
const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
|
||||
const ConstructionContext *CC, EvalCallOptions &CallOpts);
|
||||
/// the actual behavior of the program. The Idx parameter is used if we
|
||||
/// construct an array of objects. In that case it points to the index
|
||||
/// of the continous memory region.
|
||||
/// E.g.:
|
||||
/// For `int arr[4]` this index can be 0,1,2,3.
|
||||
/// For `int arr2[3][3]` this index can be 0,1,...,7,8.
|
||||
/// A multi-dimensional array is also a continous memory location in a
|
||||
/// row major order, so for arr[0][0] Idx is 0 and for arr[2][2] Idx is 8.
|
||||
SVal computeObjectUnderConstruction(const Expr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const ConstructionContext *CC,
|
||||
EvalCallOptions &CallOpts,
|
||||
unsigned Idx = 0);
|
||||
|
||||
/// Update the program state with all the path-sensitive information
|
||||
/// that's necessary to perform construction of an object with a given
|
||||
@ -724,12 +738,16 @@ class ExprEngine {
|
||||
|
||||
/// A convenient wrapper around computeObjectUnderConstruction
|
||||
/// and updateObjectsUnderConstruction.
|
||||
std::pair<ProgramStateRef, SVal> handleConstructionContext(
|
||||
const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
|
||||
const ConstructionContext *CC, EvalCallOptions &CallOpts) {
|
||||
SVal V = computeObjectUnderConstruction(E, State, LCtx, CC, CallOpts);
|
||||
return std::make_pair(
|
||||
updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts), V);
|
||||
std::pair<ProgramStateRef, SVal>
|
||||
handleConstructionContext(const Expr *E, ProgramStateRef State,
|
||||
const LocationContext *LCtx,
|
||||
const ConstructionContext *CC,
|
||||
EvalCallOptions &CallOpts, unsigned Idx = 0) {
|
||||
|
||||
SVal V = computeObjectUnderConstruction(E, State, LCtx, CC, CallOpts, Idx);
|
||||
State = updateObjectsUnderConstruction(V, E, State, LCtx, CC, CallOpts);
|
||||
|
||||
return std::make_pair(State, V);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -796,6 +814,15 @@ class ExprEngine {
|
||||
const ExplodedNode *Pred,
|
||||
const EvalCallOptions &CallOpts = {});
|
||||
|
||||
/// Checks whether our policies allow us to inline a non-POD type array
|
||||
/// construction.
|
||||
bool shouldInlineArrayConstruction(const ArrayType *Type);
|
||||
|
||||
/// Checks whether we construct an array of non-POD type, and decides if the
|
||||
/// constructor should be inkoved once again.
|
||||
bool shouldRepeatCtorCall(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
void inlineCall(WorkList *WList, const CallEvent &Call, const Decl *D,
|
||||
NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State);
|
||||
|
||||
@ -838,7 +865,7 @@ class ExprEngine {
|
||||
const Expr *InitWithAdjustments, const Expr *Result = nullptr,
|
||||
const SubRegion **OutRegionWithAdjustments = nullptr);
|
||||
|
||||
/// Returns a region representing the first element of a (possibly
|
||||
/// Returns a region representing the `Idx`th element of a (possibly
|
||||
/// multi-dimensional) array, for the purposes of element construction or
|
||||
/// destruction.
|
||||
///
|
||||
@ -846,8 +873,8 @@ class ExprEngine {
|
||||
///
|
||||
/// If the type is not an array type at all, the original value is returned.
|
||||
/// Otherwise the "IsArray" flag is set.
|
||||
static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue,
|
||||
QualType &Ty, bool &IsArray);
|
||||
static SVal makeElementRegion(ProgramStateRef State, SVal LValue,
|
||||
QualType &Ty, bool &IsArray, unsigned Idx = 0);
|
||||
|
||||
/// For a DeclStmt or CXXInitCtorInitializer, walk backward in the current CFG
|
||||
/// block to find the constructor expression that directly constructed into
|
||||
@ -878,6 +905,17 @@ class ExprEngine {
|
||||
const ObjCForCollectionStmt *O,
|
||||
const LocationContext *LC);
|
||||
private:
|
||||
/// Assuming we construct an array of non-POD types, this method allows us
|
||||
/// to store which element is to be constructed next.
|
||||
static ProgramStateRef
|
||||
setIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx, unsigned Idx);
|
||||
|
||||
static ProgramStateRef
|
||||
removeIndexOfElementToConstruct(ProgramStateRef State,
|
||||
const CXXConstructExpr *E,
|
||||
const LocationContext *LCtx);
|
||||
|
||||
/// Store the location of a C++ object corresponding to a statement
|
||||
/// until the statement is actually encountered. For example, if a DeclStmt
|
||||
/// has CXXConstructExpr as its initializer, the object would be considered
|
||||
|
@ -1364,6 +1364,7 @@ class MemRegionManager {
|
||||
~MemRegionManager();
|
||||
|
||||
ASTContext &getContext() { return Ctx; }
|
||||
const ASTContext &getContext() const { return Ctx; }
|
||||
|
||||
llvm::BumpPtrAllocator &getAllocator() { return A; }
|
||||
|
||||
|
@ -75,39 +75,6 @@ class SValBuilder {
|
||||
/// The width of the scalar type used for array indices.
|
||||
const unsigned ArrayIndexWidth;
|
||||
|
||||
SVal evalCastKind(UndefinedVal V, QualType CastTy, QualType OriginalTy);
|
||||
SVal evalCastKind(UnknownVal V, QualType CastTy, QualType OriginalTy);
|
||||
SVal evalCastKind(Loc V, QualType CastTy, QualType OriginalTy);
|
||||
SVal evalCastKind(NonLoc V, QualType CastTy, QualType OriginalTy);
|
||||
SVal evalCastSubKind(loc::ConcreteInt V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(loc::GotoLabel V, QualType CastTy, QualType OriginalTy);
|
||||
SVal evalCastSubKind(loc::MemRegionVal V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::CompoundVal V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::ConcreteInt V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::LazyCompoundVal V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::LocAsInteger V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::SymbolVal V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
SVal evalCastSubKind(nonloc::PointerToMember V, QualType CastTy,
|
||||
QualType OriginalTy);
|
||||
/// 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);
|
||||
|
||||
public:
|
||||
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
|
||||
ProgramStateManager &stateMgr);
|
||||
|
@ -169,6 +169,11 @@ class SVal {
|
||||
/// should continue to the base regions if the region is not symbolic.
|
||||
SymbolRef getAsSymbol(bool IncludeBaseRegions = false) const;
|
||||
|
||||
/// If this SVal is loc::ConcreteInt or nonloc::ConcreteInt,
|
||||
/// return a pointer to APSInt which is held in it.
|
||||
/// Otherwise, return nullptr.
|
||||
const llvm::APSInt *getAsInteger() const;
|
||||
|
||||
const MemRegion *getAsRegion() const;
|
||||
|
||||
/// printJson - Pretty-prints in JSON format.
|
||||
|
@ -68,7 +68,9 @@ struct FullDependenciesResult {
|
||||
class DependencyScanningTool {
|
||||
public:
|
||||
/// Construct a dependency scanning tool.
|
||||
DependencyScanningTool(DependencyScanningService &Service);
|
||||
DependencyScanningTool(DependencyScanningService &Service,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
|
||||
llvm::vfs::createPhysicalFileSystem());
|
||||
|
||||
/// Print out the dependency information into a string using the dependency
|
||||
/// file format that is specified in the options (-MD is the default) and
|
||||
|
@ -52,7 +52,8 @@ class DependencyConsumer {
|
||||
/// using the regular processing run.
|
||||
class DependencyScanningWorker {
|
||||
public:
|
||||
DependencyScanningWorker(DependencyScanningService &Service);
|
||||
DependencyScanningWorker(DependencyScanningService &Service,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
|
||||
|
||||
/// Run the dependency scanning tool for a given clang driver command-line,
|
||||
/// and report the discovered dependencies to the provided consumer. If \p
|
||||
|
@ -50,7 +50,7 @@ struct IncludeStyle {
|
||||
|
||||
/// Dependent on the value, multiple ``#include`` blocks can be sorted
|
||||
/// as one and divided based on category.
|
||||
/// \version 7
|
||||
/// \version 6
|
||||
IncludeBlocksStyle IncludeBlocks;
|
||||
|
||||
/// See documentation of ``IncludeCategories``.
|
||||
@ -114,7 +114,7 @@ struct IncludeStyle {
|
||||
/// Priority: 1
|
||||
/// SortPriority: 0
|
||||
/// \endcode
|
||||
/// \version 7
|
||||
/// \version 3.8
|
||||
std::vector<IncludeCategory> IncludeCategories;
|
||||
|
||||
/// Specify a regular expression of suffixes that are allowed in the
|
||||
@ -128,7 +128,7 @@ struct IncludeStyle {
|
||||
///
|
||||
/// For example, if configured to "(_test)?$", then a header a.h would be seen
|
||||
/// as the "main" include in both a.cc and a_test.cc.
|
||||
/// \version 7
|
||||
/// \version 3.9
|
||||
std::string IncludeIsMainRegex;
|
||||
|
||||
/// Specify a regular expression for files being formatted
|
||||
@ -149,7 +149,7 @@ struct IncludeStyle {
|
||||
/// also being respected in later phase). Without this option set,
|
||||
/// ``ClassImpl.hpp`` would not have the main include file put on top
|
||||
/// before any other include.
|
||||
/// \version 7
|
||||
/// \version 10
|
||||
std::string IncludeIsMainSourceRegex;
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Tooling/Syntax/Nodes.h"
|
||||
#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
|
||||
#include "clang/Tooling/Syntax/Tree.h"
|
||||
|
||||
namespace clang {
|
||||
@ -21,19 +22,21 @@ namespace syntax {
|
||||
/// Build a syntax tree for the main file.
|
||||
/// This usually covers the whole TranslationUnitDecl, but can be restricted by
|
||||
/// the ASTContext's traversal scope.
|
||||
syntax::TranslationUnit *buildSyntaxTree(Arena &A, ASTContext &Context);
|
||||
syntax::TranslationUnit *
|
||||
buildSyntaxTree(Arena &A, TokenBufferTokenManager &TBTM, ASTContext &Context);
|
||||
|
||||
// Create syntax trees from subtrees not backed by the source code.
|
||||
|
||||
// Synthesis of Leafs
|
||||
/// Create `Leaf` from token with `Spelling` and assert it has the desired
|
||||
/// `TokenKind`.
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, tok::TokenKind K,
|
||||
StringRef Spelling);
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, TokenBufferTokenManager &TBTM,
|
||||
tok::TokenKind K, StringRef Spelling);
|
||||
|
||||
/// Infer the token spelling from its `TokenKind`, then create `Leaf` from
|
||||
/// this token
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, tok::TokenKind K);
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, TokenBufferTokenManager &TBTM,
|
||||
tok::TokenKind K);
|
||||
|
||||
// Synthesis of Trees
|
||||
/// Creates the concrete syntax node according to the specified `NodeKind` `K`.
|
||||
@ -44,7 +47,8 @@ createTree(syntax::Arena &A,
|
||||
syntax::NodeKind K);
|
||||
|
||||
// Synthesis of Syntax Nodes
|
||||
syntax::EmptyStatement *createEmptyStatement(syntax::Arena &A);
|
||||
syntax::EmptyStatement *createEmptyStatement(syntax::Arena &A,
|
||||
TokenBufferTokenManager &TBTM);
|
||||
|
||||
/// Creates a completely independent copy of `N` with its macros expanded.
|
||||
///
|
||||
@ -52,7 +56,9 @@ syntax::EmptyStatement *createEmptyStatement(syntax::Arena &A);
|
||||
/// * Detached, i.e. `Parent == NextSibling == nullptr` and
|
||||
/// `Role == Detached`.
|
||||
/// * Synthesized, i.e. `Original == false`.
|
||||
syntax::Node *deepCopyExpandingMacros(syntax::Arena &A, const syntax::Node *N);
|
||||
syntax::Node *deepCopyExpandingMacros(syntax::Arena &A,
|
||||
TokenBufferTokenManager &TBTM,
|
||||
const syntax::Node *N);
|
||||
} // namespace syntax
|
||||
} // namespace clang
|
||||
#endif
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "clang/Tooling/Core/Replacement.h"
|
||||
#include "clang/Tooling/Syntax/Nodes.h"
|
||||
#include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
|
||||
#include "clang/Tooling/Syntax/Tree.h"
|
||||
|
||||
namespace clang {
|
||||
@ -20,7 +21,7 @@ namespace syntax {
|
||||
|
||||
/// Computes textual replacements required to mimic the tree modifications made
|
||||
/// to the syntax tree.
|
||||
tooling::Replacements computeReplacements(const Arena &A,
|
||||
tooling::Replacements computeReplacements(const TokenBufferTokenManager &TBTM,
|
||||
const syntax::TranslationUnit &TU);
|
||||
|
||||
/// Removes a statement or replaces it with an empty statement where one is
|
||||
@ -29,7 +30,8 @@ tooling::Replacements computeReplacements(const Arena &A,
|
||||
/// One can remove `foo();` completely and to remove `bar();` we would need to
|
||||
/// replace it with an empty statement.
|
||||
/// EXPECTS: S->canModify() == true
|
||||
void removeStatement(syntax::Arena &A, syntax::Statement *S);
|
||||
void removeStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM,
|
||||
syntax::Statement *S);
|
||||
|
||||
} // namespace syntax
|
||||
} // namespace clang
|
||||
|
@ -21,13 +21,8 @@
|
||||
#ifndef LLVM_CLANG_TOOLING_SYNTAX_NODES_H
|
||||
#define LLVM_CLANG_TOOLING_SYNTAX_NODES_H
|
||||
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Tooling/Syntax/Tokens.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "clang/Tooling/Syntax/Tree.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
namespace clang {
|
||||
namespace syntax {
|
||||
|
||||
|
@ -0,0 +1,70 @@
|
||||
//===- TokenBufferTokenManager.h -----------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLING_SYNTAX_TOKEN_BUFFER_TOKEN_MANAGER_H
|
||||
#define LLVM_CLANG_TOOLING_SYNTAX_TOKEN_BUFFER_TOKEN_MANAGER_H
|
||||
|
||||
#include "clang/Tooling/Syntax/TokenManager.h"
|
||||
#include "clang/Tooling/Syntax/Tokens.h"
|
||||
|
||||
namespace clang {
|
||||
namespace syntax {
|
||||
|
||||
/// A TokenBuffer-powered token manager.
|
||||
/// It tracks the underlying token buffers, source manager, etc.
|
||||
class TokenBufferTokenManager : public TokenManager {
|
||||
public:
|
||||
TokenBufferTokenManager(const TokenBuffer &Tokens,
|
||||
const LangOptions &LangOpts, SourceManager &SourceMgr)
|
||||
: Tokens(Tokens), LangOpts(LangOpts), SM(SourceMgr) {}
|
||||
|
||||
static bool classof(const TokenManager *N) { return N->kind() == Kind; }
|
||||
llvm::StringLiteral kind() const override { return Kind; }
|
||||
|
||||
llvm::StringRef getText(Key I) const override {
|
||||
const auto *Token = getToken(I);
|
||||
assert(Token);
|
||||
// Handle 'eof' separately, calling text() on it produces an empty string.
|
||||
// FIXME: this special logic is for syntax::Leaf dump, move it when we
|
||||
// have a direct way to retrive token kind in the syntax::Leaf.
|
||||
if (Token->kind() == tok::eof)
|
||||
return "<eof>";
|
||||
return Token->text(SM);
|
||||
}
|
||||
|
||||
const syntax::Token *getToken(Key I) const {
|
||||
return reinterpret_cast<const syntax::Token *>(I);
|
||||
}
|
||||
SourceManager &sourceManager() { return SM; }
|
||||
const SourceManager &sourceManager() const { return SM; }
|
||||
const TokenBuffer &tokenBuffer() const { return Tokens; }
|
||||
|
||||
private:
|
||||
// This manager is powered by the TokenBuffer.
|
||||
static constexpr llvm::StringLiteral Kind = "TokenBuffer";
|
||||
|
||||
/// Add \p Buffer to the underlying source manager, tokenize it and store the
|
||||
/// resulting tokens. Used exclusively in `FactoryImpl` to materialize tokens
|
||||
/// that were not written in user code.
|
||||
std::pair<FileID, ArrayRef<Token>>
|
||||
lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
|
||||
friend class FactoryImpl;
|
||||
|
||||
const TokenBuffer &Tokens;
|
||||
const LangOptions &LangOpts;
|
||||
|
||||
/// The underlying source manager for the ExtraTokens.
|
||||
SourceManager &SM;
|
||||
/// IDs and storage for additional tokenized files.
|
||||
llvm::DenseMap<FileID, std::vector<Token>> ExtraTokens;
|
||||
};
|
||||
|
||||
} // namespace syntax
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLING_SYNTAX_TOKEN_BUFFER_TOKEN_MANAGER_H
|
@ -0,0 +1,47 @@
|
||||
//===- TokenManager.h - Manage Tokens for syntax-tree ------------*- C++-*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines Token interfaces for the clang syntax-tree. This is the level of
|
||||
// abstraction that the syntax-tree uses to operate on Token.
|
||||
//
|
||||
// TokenManager decouples the syntax-tree from a particular token
|
||||
// implementation. For example, a TokenBuffer captured from a clang parser may
|
||||
// track macro expansions and associate tokens with clang's SourceManager, while
|
||||
// a clang pseudoparser would use a flat array of raw-lexed tokens in memory.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLING_SYNTAX_TOKEN_MANAGER_H
|
||||
#define LLVM_CLANG_TOOLING_SYNTAX_TOKEN_MANAGER_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace clang {
|
||||
namespace syntax {
|
||||
|
||||
/// Defines interfaces for operating "Token" in the clang syntax-tree.
|
||||
class TokenManager {
|
||||
public:
|
||||
virtual ~TokenManager() = default;
|
||||
|
||||
/// Describes what the exact class kind of the TokenManager is.
|
||||
virtual llvm::StringLiteral kind() const = 0;
|
||||
|
||||
/// A key to identify a specific token. The token concept depends on the
|
||||
/// underlying implementation -- it can be a spelled token from the original
|
||||
/// source file or an expanded token.
|
||||
/// The syntax-tree Leaf node holds a Key.
|
||||
using Key = uintptr_t;
|
||||
virtual llvm::StringRef getText(Key K) const = 0;
|
||||
};
|
||||
|
||||
} // namespace syntax
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLING_SYNTAX_TOKEN_MANAGER_H
|
@ -27,7 +27,6 @@
|
||||
#ifndef LLVM_CLANG_TOOLING_SYNTAX_TOKENS_H
|
||||
#define LLVM_CLANG_TOOLING_SYNTAX_TOKENS_H
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Defines the basic structure of the syntax tree. There are two kinds of nodes:
|
||||
// - leaf nodes correspond to a token in the expanded token stream,
|
||||
// - leaf nodes correspond to tokens,
|
||||
// - tree nodes correspond to language grammar constructs.
|
||||
//
|
||||
// The tree is initially built from an AST. Each node of a newly built tree
|
||||
@ -21,48 +21,22 @@
|
||||
#ifndef LLVM_CLANG_TOOLING_SYNTAX_TREE_H
|
||||
#define LLVM_CLANG_TOOLING_SYNTAX_TREE_H
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Tooling/Syntax/Tokens.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "clang/Tooling/Syntax/TokenManager.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace syntax {
|
||||
|
||||
/// A memory arena for syntax trees. Also tracks the underlying token buffers,
|
||||
/// source manager, etc.
|
||||
/// A memory arena for syntax trees.
|
||||
// FIXME: use BumpPtrAllocator directly.
|
||||
class Arena {
|
||||
public:
|
||||
Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
|
||||
const TokenBuffer &Tokens);
|
||||
|
||||
const SourceManager &getSourceManager() const { return SourceMgr; }
|
||||
const LangOptions &getLangOptions() const { return LangOpts; }
|
||||
|
||||
const TokenBuffer &getTokenBuffer() const;
|
||||
llvm::BumpPtrAllocator &getAllocator() { return Allocator; }
|
||||
|
||||
private:
|
||||
/// Add \p Buffer to the underlying source manager, tokenize it and store the
|
||||
/// resulting tokens. Used exclusively in `FactoryImpl` to materialize tokens
|
||||
/// that were not written in user code.
|
||||
std::pair<FileID, ArrayRef<Token>>
|
||||
lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
|
||||
friend class FactoryImpl;
|
||||
|
||||
private:
|
||||
SourceManager &SourceMgr;
|
||||
const LangOptions &LangOpts;
|
||||
const TokenBuffer &Tokens;
|
||||
/// IDs and storage for additional tokenized files.
|
||||
llvm::DenseMap<FileID, std::vector<Token>> ExtraTokens;
|
||||
/// Keeps all the allocated nodes and their intermediate data structures.
|
||||
llvm::BumpPtrAllocator Allocator;
|
||||
};
|
||||
@ -122,9 +96,9 @@ class Node {
|
||||
Node *getPreviousSibling() { return PreviousSibling; }
|
||||
|
||||
/// Dumps the structure of a subtree. For debugging and testing purposes.
|
||||
std::string dump(const SourceManager &SM) const;
|
||||
std::string dump(const TokenManager &SM) const;
|
||||
/// Dumps the tokens forming this subtree.
|
||||
std::string dumpTokens(const SourceManager &SM) const;
|
||||
std::string dumpTokens(const TokenManager &SM) const;
|
||||
|
||||
/// Asserts invariants on this node of the tree and its immediate children.
|
||||
/// Will not recurse into the subtree. No-op if NDEBUG is set.
|
||||
@ -153,16 +127,17 @@ class Node {
|
||||
unsigned CanModify : 1;
|
||||
};
|
||||
|
||||
/// A leaf node points to a single token inside the expanded token stream.
|
||||
/// A leaf node points to a single token.
|
||||
// FIXME: add TokenKind field (borrow some bits from the Node::kind).
|
||||
class Leaf final : public Node {
|
||||
public:
|
||||
Leaf(const Token *T);
|
||||
Leaf(TokenManager::Key K);
|
||||
static bool classof(const Node *N);
|
||||
|
||||
const Token *getToken() const { return Tok; }
|
||||
TokenManager::Key getTokenKey() const { return K; }
|
||||
|
||||
private:
|
||||
const Token *Tok;
|
||||
TokenManager::Key K;
|
||||
};
|
||||
|
||||
/// A node that has children and represents a syntactic language construct.
|
||||
|
@ -71,10 +71,17 @@ module Clang_Basic {
|
||||
textual header "Basic/RISCVVTypes.def"
|
||||
textual header "Basic/Sanitizers.def"
|
||||
textual header "Basic/TargetCXXABI.def"
|
||||
textual header "Basic/TokenKinds.def"
|
||||
|
||||
module * { export * }
|
||||
}
|
||||
module Clang_Basic_TokenKinds {
|
||||
requires cplusplus
|
||||
|
||||
header "Basic/TokenKinds.h"
|
||||
textual header "Basic/TokenKinds.def"
|
||||
|
||||
export *
|
||||
}
|
||||
|
||||
module Clang_CodeGen { requires cplusplus umbrella "CodeGen" module * { export * } }
|
||||
module Clang_Config { requires cplusplus umbrella "Config" module * { export * } }
|
||||
@ -182,5 +189,8 @@ module Clang_ToolingCore {
|
||||
|
||||
module Clang_ToolingInclusions {
|
||||
requires cplusplus
|
||||
umbrella "Tooling/Inclusions" module * { export * }
|
||||
umbrella "Tooling/Inclusions"
|
||||
textual header "Tooling/Inclusions/CSymbolMap.inc"
|
||||
textual header "Tooling/Inclusions/StdSymbolMap.inc"
|
||||
module * { export * }
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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())
|
||||
|
@ -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())
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 @@ class DebugStringGenerator {
|
||||
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 @@ Constraints
|
||||
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);
|
||||
|
@ -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;
|
||||
|
@ -32,4 +32,4 @@ void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) {
|
||||
|
||||
Res.push_back(Target[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() &&
|
||||
|
389
contrib/llvm-project/clang/lib/Basic/Sarif.cpp
Normal file
389
contrib/llvm-project/clang/lib/Basic/Sarif.cpp
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -10,6 +10,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CGCUDARuntime.h"
|
||||
#include "CGCXXABI.h"
|
||||
#include "CGObjCRuntime.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;
|
||||
|
@ -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);
|
||||
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, CXXGlobalInits);
|
||||
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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -34,7 +34,8 @@ namespace llvm {
|
||||
|
||||
namespace clang {
|
||||
namespace CodeGen {
|
||||
class CodeGenFunction;
|
||||
class CGFunctionInfo;
|
||||
class CodeGenFunction;
|
||||
}
|
||||
|
||||
class FieldDecl;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
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 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
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 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// 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 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
/// 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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
||||
|
@ -198,6 +198,12 @@ class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool {
|
||||
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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -303,6 +303,7 @@ class ExtractAPIVisitor : public RecursiveASTVisitor<ExtractAPIVisitor> {
|
||||
// Skip templated functions.
|
||||
switch (Decl->getTemplatedKind()) {
|
||||
case FunctionDecl::TK_NonTemplate:
|
||||
case FunctionDecl::TK_DependentNonTemplate:
|
||||
break;
|
||||
case FunctionDecl::TK_MemberSpecialization:
|
||||
case FunctionDecl::TK_FunctionTemplateSpecialization:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user