1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-11-28 08:02:54 +00:00

Merge llvm-project main llvmorg-15-init-17826-g1f8ae9d7e7e4

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvmorg-15-init-17826-g1f8ae9d7e7e4, the last commit before
the upstream release/16.x branch was created.

PR:		265425
MFC after:	2 weeks
This commit is contained in:
Dimitry Andric 2022-07-27 22:11:54 +02:00
commit 972a253a57
438 changed files with 9700 additions and 4716 deletions

View File

@ -202,7 +202,8 @@ class CFGCXXRecordTypedCall : public CFGStmt {
isa<ReturnedValueConstructionContext>(C) ||
isa<VariableConstructionContext>(C) ||
isa<ConstructorInitializerConstructionContext>(C) ||
isa<ArgumentConstructionContext>(C)));
isa<ArgumentConstructionContext>(C) ||
isa<LambdaCaptureConstructionContext>(C)));
Data2.setPointer(const_cast<ConstructionContext *>(C));
}

View File

@ -36,13 +36,14 @@ class ConstructionContextItem {
ElidedDestructorKind,
ElidableConstructorKind,
ArgumentKind,
STATEMENT_WITH_INDEX_KIND_BEGIN=ArgumentKind,
STATEMENT_WITH_INDEX_KIND_END=ArgumentKind,
LambdaCaptureKind,
STATEMENT_WITH_INDEX_KIND_BEGIN = ArgumentKind,
STATEMENT_WITH_INDEX_KIND_END = LambdaCaptureKind,
STATEMENT_KIND_BEGIN = VariableKind,
STATEMENT_KIND_END = ArgumentKind,
STATEMENT_KIND_END = LambdaCaptureKind,
InitializerKind,
INITIALIZER_KIND_BEGIN=InitializerKind,
INITIALIZER_KIND_END=InitializerKind
INITIALIZER_KIND_BEGIN = InitializerKind,
INITIALIZER_KIND_END = InitializerKind
};
LLVM_DUMP_METHOD static StringRef getKindAsString(ItemKind K) {
@ -55,6 +56,8 @@ class ConstructionContextItem {
case ElidedDestructorKind: return "elide destructor";
case ElidableConstructorKind: return "elide constructor";
case ArgumentKind: return "construct into argument";
case LambdaCaptureKind:
return "construct into lambda captured variable";
case InitializerKind: return "construct into member variable";
};
llvm_unreachable("Unknown ItemKind");
@ -72,7 +75,7 @@ class ConstructionContextItem {
bool hasIndex() const {
return Kind >= STATEMENT_WITH_INDEX_KIND_BEGIN &&
Kind >= STATEMENT_WITH_INDEX_KIND_END;
Kind <= STATEMENT_WITH_INDEX_KIND_END;
}
bool hasInitializer() const {
@ -127,6 +130,9 @@ class ConstructionContextItem {
ConstructionContextItem(const CXXCtorInitializer *Init)
: Data(Init), Kind(InitializerKind), Index(0) {}
ConstructionContextItem(const LambdaExpr *LE, unsigned Index)
: Data(LE), Kind(LambdaCaptureKind), Index(Index) {}
ItemKind getKind() const { return Kind; }
LLVM_DUMP_METHOD StringRef getKindAsString() const {
@ -254,7 +260,8 @@ class ConstructionContext {
CXX17ElidedCopyReturnedValueKind,
RETURNED_VALUE_BEGIN = SimpleReturnedValueKind,
RETURNED_VALUE_END = CXX17ElidedCopyReturnedValueKind,
ArgumentKind
ArgumentKind,
LambdaCaptureKind
};
protected:
@ -298,6 +305,11 @@ class ConstructionContext {
const ConstructionContextLayer *TopLayer);
Kind getKind() const { return K; }
virtual const ArrayInitLoopExpr *getArrayInitLoop() const { return nullptr; }
// Only declared to silence -Wnon-virtual-dtor warnings.
virtual ~ConstructionContext() = default;
};
/// An abstract base class for local variable constructors.
@ -314,6 +326,12 @@ class VariableConstructionContext : public ConstructionContext {
public:
const DeclStmt *getDeclStmt() const { return DS; }
const ArrayInitLoopExpr *getArrayInitLoop() const override {
const auto *Var = cast<VarDecl>(DS->getSingleDecl());
return dyn_cast<ArrayInitLoopExpr>(Var->getInit());
}
static bool classof(const ConstructionContext *CC) {
return CC->getKind() >= VARIABLE_BEGIN &&
CC->getKind() <= VARIABLE_END;
@ -381,6 +399,10 @@ class ConstructorInitializerConstructionContext : public ConstructionContext {
public:
const CXXCtorInitializer *getCXXCtorInitializer() const { return I; }
const ArrayInitLoopExpr *getArrayInitLoop() const override {
return dyn_cast<ArrayInitLoopExpr>(I->getInit());
}
static bool classof(const ConstructionContext *CC) {
return CC->getKind() >= INITIALIZER_BEGIN &&
CC->getKind() <= INITIALIZER_END;
@ -659,6 +681,42 @@ class ArgumentConstructionContext : public ConstructionContext {
}
};
class LambdaCaptureConstructionContext : public ConstructionContext {
// The lambda of which the initializer we capture.
const LambdaExpr *LE;
// Index of the captured element in the captured list.
unsigned Index;
friend class ConstructionContext; // Allows to create<>() itself.
explicit LambdaCaptureConstructionContext(const LambdaExpr *LE,
unsigned Index)
: ConstructionContext(LambdaCaptureKind), LE(LE), Index(Index) {}
public:
const LambdaExpr *getLambdaExpr() const { return LE; }
unsigned getIndex() const { return Index; }
const Expr *getInitializer() const {
return *(LE->capture_init_begin() + Index);
}
const FieldDecl *getFieldDecl() const {
auto It = LE->getLambdaClass()->field_begin();
std::advance(It, Index);
return *It;
}
const ArrayInitLoopExpr *getArrayInitLoop() const override {
return dyn_cast_or_null<ArrayInitLoopExpr>(getInitializer());
}
static bool classof(const ConstructionContext *CC) {
return CC->getKind() == LambdaCaptureKind;
}
};
} // end namespace clang
#endif // LLVM_CLANG_ANALYSIS_CONSTRUCTIONCONTEXT_H

View File

@ -340,6 +340,10 @@ class DataflowAnalysisContext {
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
DisjunctionVals;
llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *>
ImplicationVals;
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *>
BiconditionalVals;
// Flow conditions are tracked symbolically: each unique flow condition is
// associated with a fresh symbolic variable (token), bound to the clause that

View File

@ -128,6 +128,21 @@ class Environment {
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
/// Creates and returns an environment to use for an inline analysis of the
/// callee. Uses the storage location from each argument in the `Call` as the
/// storage location for the corresponding parameter in the callee.
///
/// Requirements:
///
/// The callee of `Call` must be a `FunctionDecl` with a body.
///
/// The body of the callee must not reference globals.
///
/// The arguments of `Call` must map 1:1 to the callee's parameters.
///
/// Each argument of `Call` must already have a `StorageLocation`.
Environment pushCall(const CallExpr *Call) const;
/// Returns true if and only if the environment is equivalent to `Other`, i.e
/// the two environments:
/// - have the same mappings from declarations to storage locations,

View File

@ -54,10 +54,13 @@ template <typename Key, typename ElementLattice> class MapLattice {
// The `bottom` element is the empty map.
static MapLattice bottom() { return MapLattice(); }
void insert(const std::pair<const key_type, mapped_type> &P) { C.insert(P); }
std::pair<iterator, bool>
insert(const std::pair<const key_type, mapped_type> &P) {
return C.insert(P);
}
void insert(std::pair<const key_type, mapped_type> &&P) {
C.insert(std::move(P));
std::pair<iterator, bool> insert(std::pair<const key_type, mapped_type> &&P) {
return C.insert(std::move(P));
}
unsigned size() const { return C.size(); }

View File

@ -20,6 +20,12 @@
namespace clang {
namespace dataflow {
struct TransferOptions {
/// Determines whether to analyze function bodies when present in the
/// translation unit.
bool ContextSensitive = false;
};
/// Maps statements to the environments of basic blocks that contain them.
class StmtToEnvMap {
public:
@ -36,7 +42,8 @@ class StmtToEnvMap {
/// Requirements:
///
/// `S` must not be `ParenExpr` or `ExprWithCleanups`.
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env);
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
TransferOptions Options);
} // namespace dataflow
} // namespace clang

View File

@ -23,6 +23,7 @@
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Transfer.h"
#include "llvm/ADT/Any.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Error.h"
@ -36,6 +37,9 @@ struct DataflowAnalysisOptions {
// (at which point the built-in transfer functions can be simply a standalone
// analysis).
bool ApplyBuiltinTransfer = true;
/// Only has an effect if `ApplyBuiltinTransfer` is true.
TransferOptions BuiltinTransferOptions;
};
/// Type-erased lattice element container.
@ -57,7 +61,7 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel {
/// Deprecated. Use the `DataflowAnalysisOptions` constructor instead.
TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer)
: Options({ApplyBuiltinTransfer}) {}
: Options({ApplyBuiltinTransfer, TransferOptions{}}) {}
TypeErasedDataflowAnalysis(DataflowAnalysisOptions Options)
: Options(Options) {}
@ -90,6 +94,11 @@ 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 Options.ApplyBuiltinTransfer; }
/// Returns the options to be passed to the built-in transfer functions.
TransferOptions builtinTransferOptions() const {
return Options.BuiltinTransferOptions;
}
};
/// Type-erased model of the program at a given program point.

View File

@ -37,12 +37,13 @@ class Value {
Pointer,
Struct,
// Synthetic boolean values are either atomic values or composites that
// represent conjunctions, disjunctions, and negations.
// Synthetic boolean values are either atomic values or logical connectives.
AtomicBool,
Conjunction,
Disjunction,
Negation
Negation,
Implication,
Biconditional,
};
explicit Value(Kind ValKind) : ValKind(ValKind) {}
@ -84,7 +85,9 @@ class BoolValue : public Value {
return Val->getKind() == Kind::AtomicBool ||
Val->getKind() == Kind::Conjunction ||
Val->getKind() == Kind::Disjunction ||
Val->getKind() == Kind::Negation;
Val->getKind() == Kind::Negation ||
Val->getKind() == Kind::Implication ||
Val->getKind() == Kind::Biconditional;
}
};
@ -162,6 +165,54 @@ class NegationValue : public BoolValue {
BoolValue &SubVal;
};
/// Models a boolean implication.
///
/// Equivalent to `!LHS v RHS`.
class ImplicationValue : public BoolValue {
public:
explicit ImplicationValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
: BoolValue(Kind::Implication), LeftSubVal(LeftSubVal),
RightSubVal(RightSubVal) {}
static bool classof(const Value *Val) {
return Val->getKind() == Kind::Implication;
}
/// Returns the left sub-value of the implication.
BoolValue &getLeftSubValue() const { return LeftSubVal; }
/// Returns the right sub-value of the implication.
BoolValue &getRightSubValue() const { return RightSubVal; }
private:
BoolValue &LeftSubVal;
BoolValue &RightSubVal;
};
/// Models a boolean biconditional.
///
/// Equivalent to `(LHS ^ RHS) v (!LHS ^ !RHS)`.
class BiconditionalValue : public BoolValue {
public:
explicit BiconditionalValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
: BoolValue(Kind::Biconditional), LeftSubVal(LeftSubVal),
RightSubVal(RightSubVal) {}
static bool classof(const Value *Val) {
return Val->getKind() == Kind::Biconditional;
}
/// Returns the left sub-value of the biconditional.
BoolValue &getLeftSubValue() const { return LeftSubVal; }
/// Returns the right sub-value of the biconditional.
BoolValue &getRightSubValue() const { return RightSubVal; }
private:
BoolValue &LeftSubVal;
BoolValue &RightSubVal;
};
/// Models an integer.
class IntegerValue : public Value {
public:

View File

@ -5040,6 +5040,12 @@ general this requires the template to be declared at least twice. For example:
clang::preferred_name(wstring)]] basic_string {
// ...
};
Note that the ``preferred_name`` attribute will be ignored when the compiler
writes a C++20 Module interface now. This is due to a compiler issue
(https://github.com/llvm/llvm-project/issues/56490) that blocks users to modularize
declarations with `preferred_name`. This is intended to be fixed in the future.
}];
}

View File

@ -45,18 +45,18 @@ namespace clang {
// Start position for diagnostics.
enum {
DIAG_START_COMMON = 0,
DIAG_START_DRIVER = DIAG_START_COMMON + DIAG_SIZE_COMMON,
DIAG_START_FRONTEND = DIAG_START_DRIVER + DIAG_SIZE_DRIVER,
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + DIAG_SIZE_FRONTEND,
DIAG_START_LEX = DIAG_START_SERIALIZATION + DIAG_SIZE_SERIALIZATION,
DIAG_START_PARSE = DIAG_START_LEX + DIAG_SIZE_LEX,
DIAG_START_AST = DIAG_START_PARSE + DIAG_SIZE_PARSE,
DIAG_START_COMMENT = DIAG_START_AST + DIAG_SIZE_AST,
DIAG_START_CROSSTU = DIAG_START_COMMENT + DIAG_SIZE_COMMENT,
DIAG_START_SEMA = DIAG_START_CROSSTU + DIAG_SIZE_CROSSTU,
DIAG_START_ANALYSIS = DIAG_START_SEMA + DIAG_SIZE_SEMA,
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + DIAG_SIZE_ANALYSIS,
DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + DIAG_SIZE_REFACTORING
DIAG_START_DRIVER = DIAG_START_COMMON + static_cast<int>(DIAG_SIZE_COMMON),
DIAG_START_FRONTEND = DIAG_START_DRIVER + static_cast<int>(DIAG_SIZE_DRIVER),
DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + static_cast<int>(DIAG_SIZE_FRONTEND),
DIAG_START_LEX = DIAG_START_SERIALIZATION + static_cast<int>(DIAG_SIZE_SERIALIZATION),
DIAG_START_PARSE = DIAG_START_LEX + static_cast<int>(DIAG_SIZE_LEX),
DIAG_START_AST = DIAG_START_PARSE + static_cast<int>(DIAG_SIZE_PARSE),
DIAG_START_COMMENT = DIAG_START_AST + static_cast<int>(DIAG_SIZE_AST),
DIAG_START_CROSSTU = DIAG_START_COMMENT + static_cast<int>(DIAG_SIZE_COMMENT),
DIAG_START_SEMA = DIAG_START_CROSSTU + static_cast<int>(DIAG_SIZE_CROSSTU),
DIAG_START_ANALYSIS = DIAG_START_SEMA + static_cast<int>(DIAG_SIZE_SEMA),
DIAG_START_REFACTORING = DIAG_START_ANALYSIS + static_cast<int>(DIAG_SIZE_ANALYSIS),
DIAG_UPPER_LIMIT = DIAG_START_REFACTORING + static_cast<int>(DIAG_SIZE_REFACTORING)
};
class CustomDiagInfo;

View File

@ -282,7 +282,7 @@ def err_inline_nested_namespace_definition : Error<
def err_expected_semi_after_attribute_list : Error<
"expected ';' after attribute list">;
def err_expected_semi_after_static_assert : Error<
"expected ';' after static_assert">;
"expected ';' after '%0'">;
def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">;
def err_single_decl_assign_in_for_range : Error<
"range-based 'for' statement uses ':', not '='">;
@ -425,7 +425,7 @@ def err_unexpected_token_in_nested_name_spec : Error<
def err_bool_redeclaration : Error<
"redeclaration of C++ built-in type 'bool'">;
def warn_cxx98_compat_static_assert : Warning<
"static_assert declarations are incompatible with C++98">,
"'static_assert' declarations are incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
def ext_ms_static_assert : ExtWarn<
"use of 'static_assert' without inclusion of <assert.h> is a Microsoft "
@ -538,6 +538,8 @@ def err_invalid_operator_on_type : Error<
"cannot use %select{dot|arrow}0 operator on a type">;
def err_expected_unqualified_id : Error<
"expected %select{identifier|unqualified-id}0">;
def err_while_loop_outside_of_a_function : Error<
"while loop outside of a function">;
def err_brackets_go_after_unqualified_id : Error<
"brackets are not allowed here; to declare an array, "
"place the brackets after the %select{identifier|name}0">;

View File

@ -1526,12 +1526,12 @@ def err_messaging_class_with_direct_method : Error<
// C++ declarations
def err_static_assert_expression_is_not_constant : Error<
"static_assert expression is not an integral constant expression">;
"static assertion expression is not an integral constant expression">;
def err_constexpr_if_condition_expression_is_not_constant : Error<
"constexpr if condition is not a constant expression">;
def err_static_assert_failed : Error<"static_assert failed%select{: %1|}0">;
def err_static_assert_failed : Error<"static assertion failed%select{: %1|}0">;
def err_static_assert_requirement_failed : Error<
"static_assert failed due to requirement '%0'%select{: %2|}1">;
"static assertion failed due to requirement '%0'%select{: %2|}1">;
def warn_consteval_if_always_true : Warning<
"consteval if is always true in an %select{unevaluated|immediate}0 context">,
@ -5774,6 +5774,8 @@ def warn_forward_class_redefinition : Warning<
def err_redefinition_different_typedef : Error<
"%select{typedef|type alias|type alias template}0 "
"redefinition with different types%diff{ ($ vs $)|}1,2">;
def err_redefinition_different_concept : Error<
"redefinition of concept %0 with different template parameters or requirements">;
def err_tag_reference_non_tag : Error<
"%select{non-struct type|non-class type|non-union type|non-enum "
"type|typedef|type alias|template|type alias template|template "

View File

@ -195,6 +195,7 @@ VALUE_LANGOPT(DoubleSize , 32, 0, "width of double")
VALUE_LANGOPT(LongDoubleSize , 32, 0, "width of long double")
LANGOPT(PPCIEEELongDouble , 1, 0, "use IEEE 754 quadruple-precision for long double")
LANGOPT(EnableAIXExtendedAltivecABI , 1, 0, "__EXTABI__ predefined macro")
LANGOPT(EnableAIXQuadwordAtomicsABI , 1, 0, "Use 16-byte atomic lock free semantics")
COMPATIBLE_VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level")
COMPATIBLE_VALUE_LANGOPT(PIE , 1, 0, "is pie")
LANGOPT(ROPI , 1, 0, "Read-only position independence")

View File

@ -908,6 +908,9 @@ PRAGMA_ANNOTATION(pragma_fp)
// Annotation for the attribute pragma directives - #pragma clang attribute ...
PRAGMA_ANNOTATION(pragma_attribute)
// Annotation for the riscv pragma directives - #pragma clang riscv intrinsic ...
PRAGMA_ANNOTATION(pragma_riscv)
// Annotations for module import translated from #include etc.
ANNOTATION(module_include)
ANNOTATION(module_begin)

View File

@ -186,7 +186,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
// HasPolicyOperand: Has a policy operand. 0 is tail and mask undisturbed, 1 is
// tail agnostic, 2 is mask undisturbed, and 3 is tail and mask agnostic. The
// policy operand is located at the last position.
Policy MaskedPolicy = HasPolicyOperand;
Policy MaskedPolicyScheme = HasPolicyOperand;
// The policy scheme for unmasked intrinsic IR.
// It could be NonePolicy, HasPassthruOperand or HasPolicyOperand.
@ -194,7 +194,7 @@ class RVVBuiltin<string suffix, string prototype, string type_range,
// undef, tail policy is tail agnostic, otherwise policy is tail undisturbed.
// HasPolicyOperand: Has a policy operand. 1 is tail agnostic and 0 is tail
// undisturbed.
Policy UnMaskedPolicy = NonePolicy;
Policy UnMaskedPolicyScheme = NonePolicy;
// This builtin supports non-masked function overloading api.
// All masked operations support overloading api.
@ -443,7 +443,7 @@ class RVVMaskOp0Builtin<string prototype> : RVVOp0Builtin<"m", prototype, "c"> {
let HasMaskedOffOperand = false;
}
let UnMaskedPolicy = HasPolicyOperand,
let UnMaskedPolicyScheme = HasPolicyOperand,
HasMaskedOffOperand = false in {
multiclass RVVSlideBuiltinSet {
defm "" : RVVOutBuiltinSet<NAME, "csilxfd",
@ -582,7 +582,7 @@ class IsFloat<string type> {
}
let HasUnMaskedOverloaded = false,
MaskedPolicy = NonePolicy in {
MaskedPolicyScheme = NonePolicy in {
class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
let Name = "vlm_v";
let IRName = "vlm";
@ -591,7 +591,7 @@ let HasUnMaskedOverloaded = false,
}
let HasUnMaskedOverloaded = false,
UnMaskedPolicy = HasPassthruOperand in {
UnMaskedPolicyScheme = HasPassthruOperand in {
multiclass RVVVLEBuiltin<list<string> types> {
let Name = NAME # "_v",
IRName = "vle",
@ -664,7 +664,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
IRName = "vlse",
MaskedIRName ="vlse_mask",
HasUnMaskedOverloaded = false,
UnMaskedPolicy = HasPassthruOperand in {
UnMaskedPolicyScheme = HasPassthruOperand in {
foreach type = types in {
def : RVVOutBuiltin<"v", "vPCet", type>;
if !not(IsFloat<type>.val) then {
@ -675,7 +675,7 @@ multiclass RVVVLSEBuiltin<list<string> types> {
}
multiclass RVVIndexedLoad<string op> {
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
foreach type = TypeList in {
foreach eew_list = EEWList[0-2] in {
defvar eew = eew_list[0];
@ -701,7 +701,7 @@ multiclass RVVIndexedLoad<string op> {
}
let HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl)
std::swap(Ops[0], Ops[1]);
@ -738,7 +738,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
IRName = "vsse",
MaskedIRName = "vsse_mask",
HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl)
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
@ -762,7 +762,7 @@ multiclass RVVVSSEBuiltin<list<string> types> {
multiclass RVVIndexedStore<string op> {
let HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
// Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl)
std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3);
@ -1141,7 +1141,7 @@ multiclass RVVUnitStridedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, val0, val1, ..., vl)
@ -1187,7 +1187,7 @@ multiclass RVVStridedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, stride, val0, val1, ..., vl).
@ -1229,7 +1229,7 @@ multiclass RVVIndexedSegStore<string op> {
MaskedIRName = op # nf # "_mask",
NF = nf,
HasMaskedOffOperand = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
// Builtin: (ptr, index, val0, val1, ..., vl)
@ -1568,7 +1568,7 @@ def vsetvl_macro: RVVHeader;
let HasBuiltinAlias = false,
HasVL = false,
HasMasked = false,
MaskedPolicy = NonePolicy,
MaskedPolicyScheme = NonePolicy,
Log2LMUL = [0],
ManualCodegen = [{IntrinsicTypes = {ResultType};}] in // Set XLEN type
{
@ -1627,7 +1627,7 @@ defm : RVVIndexedSegStore<"vsoxseg">;
// 12. Vector Integer Arithmetic Instructions
// 12.1. Vector Single-Width Integer Add and Subtract
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vadd : RVVIntBinBuiltinSet;
defm vsub : RVVIntBinBuiltinSet;
defm vrsub : RVVOutOp1BuiltinSet<"vrsub", "csil",
@ -1638,7 +1638,7 @@ defm vneg_v : RVVPseudoUnaryBuiltin<"vrsub", "csil">;
// 12.2. Vector Widening Integer Add/Subtract
// Widening unsigned integer add/subtract, 2*SEW = SEW +/- SEW
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vwaddu : RVVUnsignedWidenBinBuiltinSet;
defm vwsubu : RVVUnsignedWidenBinBuiltinSet;
// Widening signed integer add/subtract, 2*SEW = SEW +/- SEW
@ -1657,7 +1657,7 @@ defm vwcvt_x_x_v : RVVPseudoVWCVTBuiltin<"vwadd", "vwcvt_x", "csi",
[["w", "wv"]]>;
// 12.3. Vector Integer Extension
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
def vsext_vf2 : RVVIntExt<"vsext", "w", "wv", "csi">;
def vzext_vf2 : RVVIntExt<"vzext", "Uw", "UwUv", "csi">;
@ -1673,8 +1673,8 @@ let Log2LMUL = [-3, -2, -1, 0] in {
}
// 12.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions
let HasMasked = false, MaskedPolicy = NonePolicy in {
let UnMaskedPolicy = HasPassthruOperand in {
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vadc : RVVCarryinBuiltinSet;
defm vsbc : RVVCarryinBuiltinSet;
}
@ -1685,7 +1685,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
}
// 12.5. Vector Bitwise Logical Instructions
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vand : RVVIntBinBuiltinSet;
defm vxor : RVVIntBinBuiltinSet;
defm vor : RVVIntBinBuiltinSet;
@ -1693,7 +1693,7 @@ defm vor : RVVIntBinBuiltinSet;
defm vnot_v : RVVPseudoVNotBuiltin<"vxor", "csil">;
// 12.6. Vector Single-Width Bit Shift Instructions
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vsll : RVVShiftBuiltinSet;
defm vsrl : RVVUnsignedShiftBuiltinSet;
defm vsra : RVVSignedShiftBuiltinSet;
@ -1707,7 +1707,7 @@ defm vncvt_x_x_w : RVVPseudoVNCVTBuiltin<"vnsrl", "vncvt_x", "csi",
["Uv", "UvUw"]]>;
// 12.8. Vector Integer Comparison Instructions
let MaskedPolicy = NonePolicy in {
let MaskedPolicyScheme = NonePolicy in {
defm vmseq : RVVIntMaskOutBuiltinSet;
defm vmsne : RVVIntMaskOutBuiltinSet;
defm vmsltu : RVVUnsignedMaskOutBuiltinSet;
@ -1721,7 +1721,7 @@ defm vmsge : RVVSignedMaskOutBuiltinSet;
}
// 12.9. Vector Integer Min/Max Instructions
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vminu : RVVUnsignedBinBuiltinSet;
defm vmin : RVVSignedBinBuiltinSet;
defm vmaxu : RVVUnsignedBinBuiltinSet;
@ -1745,7 +1745,7 @@ defm vrem : RVVSignedBinBuiltinSet;
}
// 12.12. Vector Widening Integer Multiply Instructions
let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicy = HasPassthruOperand in {
let Log2LMUL = [-3, -2, -1, 0, 1, 2], UnMaskedPolicyScheme = HasPassthruOperand in {
defm vwmul : RVVOutOp0Op1BuiltinSet<"vwmul", "csi",
[["vv", "w", "wvv"],
["vx", "w", "wve"]]>;
@ -1758,7 +1758,7 @@ defm vwmulsu : RVVOutOp0Op1BuiltinSet<"vwmulsu", "csi",
}
// 12.13. Vector Single-Width Integer Multiply-Add Instructions
let UnMaskedPolicy = HasPolicyOperand in {
let UnMaskedPolicyScheme = HasPolicyOperand in {
defm vmacc : RVVIntTerBuiltinSet;
defm vnmsac : RVVIntTerBuiltinSet;
defm vmadd : RVVIntTerBuiltinSet;
@ -1783,7 +1783,7 @@ defm vwmaccus : RVVOutOp1Op2BuiltinSet<"vwmaccus", "csi",
// 12.15. Vector Integer Merge Instructions
// C/C++ Operand: (mask, op1, op2, vl), Intrinsic: (op1, op2, mask, vl)
let HasMasked = false, MaskedPolicy = NonePolicy,
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
@ -1798,7 +1798,9 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
}
// 12.16. Vector Integer Move Instructions
let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NonePolicy in {
let HasMasked = false,
UnMaskedPolicyScheme = HasPassthruOperand,
MaskedPolicyScheme = NonePolicy in {
let OverloadedName = "vmv_v" in {
defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csil",
[["v", "Uv", "UvUv"]]>;
@ -1813,7 +1815,7 @@ let HasMasked = false, UnMaskedPolicy = HasPassthruOperand, MaskedPolicy = NoneP
// 13. Vector Fixed-Point Arithmetic Instructions
// 13.1. Vector Single-Width Saturating Add and Subtract
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vsaddu : RVVUnsignedBinBuiltinSet;
defm vsadd : RVVSignedBinBuiltinSet;
defm vssubu : RVVUnsignedBinBuiltinSet;
@ -1866,7 +1868,7 @@ let Log2LMUL = [-2, -1, 0, 1, 2] in {
}
// 14.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions
let UnMaskedPolicy = HasPolicyOperand in {
let UnMaskedPolicyScheme = HasPolicyOperand in {
defm vfmacc : RVVFloatingTerBuiltinSet;
defm vfnmacc : RVVFloatingTerBuiltinSet;
defm vfmsac : RVVFloatingTerBuiltinSet;
@ -1884,7 +1886,7 @@ defm vfwnmsac : RVVFloatingWidenTerBuiltinSet;
}
// 14.8. Vector Floating-Point Square-Root Instruction
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
def vfsqrt : RVVFloatingUnaryVVBuiltin;
// 14.9. Vector Floating-Point Reciprocal Square-Root Estimate Instruction
@ -1906,7 +1908,7 @@ defm vfneg_v : RVVPseudoVFUnaryBuiltin<"vfsgnjn", "xfd">;
defm vfabs_v : RVVPseudoVFUnaryBuiltin<"vfsgnjx", "xfd">;
// 14.13. Vector Floating-Point Compare Instructions
let MaskedPolicy = NonePolicy in {
let MaskedPolicyScheme = NonePolicy in {
defm vmfeq : RVVFloatingMaskOutBuiltinSet;
defm vmfne : RVVFloatingMaskOutBuiltinSet;
defm vmflt : RVVFloatingMaskOutBuiltinSet;
@ -1916,12 +1918,12 @@ defm vmfge : RVVFloatingMaskOutBuiltinSet;
}
// 14.14. Vector Floating-Point Classify Instruction
let Name = "vfclass_v", UnMaskedPolicy = HasPassthruOperand in
let Name = "vfclass_v", UnMaskedPolicyScheme = HasPassthruOperand in
def vfclass : RVVOp0Builtin<"Uv", "Uvv", "xfd">;
// 14.15. Vector Floating-Point Merge Instructio
// C/C++ Operand: (mask, op1, op2, vl), Builtin: (op1, op2, mask, vl)
let HasMasked = false, MaskedPolicy = NonePolicy,
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()};
@ -1935,13 +1937,13 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
}
// 14.16. Vector Floating-Point Move Instruction
let HasMasked = false, UnMaskedPolicy = HasPassthruOperand,
HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy in
let HasMasked = false, UnMaskedPolicyScheme = HasPassthruOperand,
HasUnMaskedOverloaded = false, MaskedPolicyScheme = NonePolicy in
defm vfmv_v : RVVOutBuiltinSet<"vfmv_v_f", "xfd",
[["f", "v", "ve"]]>;
// 14.17. Single-Width Floating-Point/Integer Type-Convert Instructions
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
def vfcvt_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_xu">;
def vfcvt_x_f_v : RVVConvToSignedBuiltin<"vfcvt_x">;
def vfcvt_rtz_xu_f_v : RVVConvToUnsignedBuiltin<"vfcvt_rtz_xu">;
@ -1975,7 +1977,7 @@ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in {
// 15. Vector Reduction Operations
// 15.1. Vector Single-Width Integer Reduction Instructions
let MaskedPolicy = NonePolicy in {
let MaskedPolicyScheme = NonePolicy in {
defm vredsum : RVVIntReductionBuiltinSet;
defm vredmaxu : RVVUnsignedReductionBuiltin;
defm vredmax : RVVSignedReductionBuiltin;
@ -2021,7 +2023,7 @@ def vmset : RVVMaskNullaryBuiltin;
defm vmmv_m : RVVPseudoMaskBuiltin<"vmand", "c">;
defm vmnot_m : RVVPseudoMaskBuiltin<"vmnand", "c">;
let MaskedPolicy = NonePolicy in {
let MaskedPolicyScheme = NonePolicy in {
// 16.2. Vector count population in mask vcpop.m
def vcpop : RVVMaskOp0Builtin<"um">;
@ -2038,7 +2040,7 @@ def vmsif : RVVMaskUnaryBuiltin;
def vmsof : RVVMaskUnaryBuiltin;
}
let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
let UnMaskedPolicyScheme = HasPassthruOperand, HasUnMaskedOverloaded = false in {
// 16.8. Vector Iota Instruction
defm viota : RVVOutBuiltinSet<"viota", "csil", [["m", "Uv", "Uvm"]]>;
@ -2049,7 +2051,7 @@ let UnMaskedPolicy = HasPassthruOperand, HasUnMaskedOverloaded = false in {
// 17. Vector Permutation Instructions
// 17.1. Integer Scalar Move Instructions
let HasMasked = false, MaskedPolicy = NonePolicy in {
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
let HasVL = false, OverloadedName = "vmv_x" in
defm vmv_x : RVVOp0BuiltinSet<"vmv_x_s", "csil",
[["s", "ve", "ev"],
@ -2061,7 +2063,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy in {
}
// 17.2. Floating-Point Scalar Move Instructions
let HasMasked = false, MaskedPolicy = NonePolicy in {
let HasMasked = false, MaskedPolicyScheme = NonePolicy in {
let HasVL = false, OverloadedName = "vfmv_f" in
defm vfmv_f : RVVOp0BuiltinSet<"vfmv_f_s", "xfd",
[["s", "ve", "ev"]]>;
@ -2078,7 +2080,7 @@ defm vslideup : RVVSlideBuiltinSet;
defm vslidedown : RVVSlideBuiltinSet;
// 17.3.3. Vector Slide1up Instructions
let UnMaskedPolicy = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPassthruOperand in {
defm vslide1up : RVVSlideOneBuiltinSet;
defm vfslide1up : RVVFloatingBinVFBuiltinSet;
@ -2104,7 +2106,7 @@ defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csil",
}
// 17.5. Vector Compress Instruction
let HasMasked = false, MaskedPolicy = NonePolicy,
let HasMasked = false, MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3);
IntrinsicTypes = {ResultType, Ops[3]->getType()};
@ -2119,7 +2121,7 @@ let HasMasked = false, MaskedPolicy = NonePolicy,
// Miscellaneous
let HasMasked = false, HasVL = false, IRName = "" in {
let Name = "vreinterpret_v", MaskedPolicy = NonePolicy,
let Name = "vreinterpret_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
return Builder.CreateBitCast(Ops[0], ResultType);
}] in {
@ -2141,7 +2143,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
let Name = "vundefined", HasUnMaskedOverloaded = false, MaskedPolicy = NonePolicy,
let Name = "vundefined", HasUnMaskedOverloaded = false,
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
return llvm::UndefValue::get(ResultType);
}] in {
@ -2151,7 +2154,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
// LMUL truncation
// C/C++ Operand: VecTy, IR Operand: VecTy, Index
let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc", MaskedPolicy = NonePolicy,
let Name = "vlmul_trunc_v", OverloadedName = "vlmul_trunc",
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{ {
ID = Intrinsic::vector_extract;
IntrinsicTypes = {ResultType, Ops[0]->getType()};
@ -2169,7 +2173,8 @@ let HasMasked = false, HasVL = false, IRName = "" in {
// LMUL extension
// C/C++ Operand: SubVecTy, IR Operand: VecTy, SubVecTy, Index
let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext", MaskedPolicy = NonePolicy,
let Name = "vlmul_ext_v", OverloadedName = "vlmul_ext",
MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
ID = Intrinsic::vector_insert;
IntrinsicTypes = {ResultType, Ops[0]->getType()};
@ -2187,7 +2192,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
let Name = "vget_v", MaskedPolicy = NonePolicy,
let Name = "vget_v", MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
ID = Intrinsic::vector_extract;
@ -2211,7 +2216,7 @@ let HasMasked = false, HasVL = false, IRName = "" in {
}
}
let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicy = NonePolicy,
let Name = "vset_v", Log2LMUL = [0, 1, 2], MaskedPolicyScheme = NonePolicy,
ManualCodegen = [{
{
ID = Intrinsic::vector_insert;

View File

@ -14,12 +14,17 @@
#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H
#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/LLVM.h"
namespace llvm {
class Constant;
class LLVMContext;
class Module;
class StringRef;
namespace vfs {
class FileSystem;
}
}
namespace clang {
@ -98,10 +103,11 @@ class CodeGenerator : public ASTConsumer {
/// the allocated CodeGenerator instance.
CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags,
llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO,
llvm::LLVMContext& C,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr);
} // end namespace clang

View File

@ -44,9 +44,7 @@ typedef SmallVector<InputInfo, 4> InputInfoList;
class Command;
class Compilation;
class JobList;
class JobAction;
class SanitizerArgs;
class ToolChain;
/// Describes the kind of LTO mode selected via -f(no-)?lto(=.*)? options.

View File

@ -3679,6 +3679,10 @@ def mabi_EQ_vec_extabi : Flag<["-"], "mabi=vec-extabi">, Group<m_Group>, Flags<[
MarshallingInfoFlag<LangOpts<"EnableAIXExtendedAltivecABI">>;
def mabi_EQ_vec_default : Flag<["-"], "mabi=vec-default">, Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Enable the default Altivec ABI on AIX (AIX only). Uses only volatile vector registers.">;
def mabi_EQ_quadword_atomics : Flag<["-"], "mabi=quadword-atomics">,
Group<m_Group>, Flags<[CC1Option]>,
HelpText<"Enable quadword atomics ABI on AIX (AIX PPC64 only). Uses lqarx/stqcx. instructions.">,
MarshallingInfoFlag<LangOpts<"EnableAIXQuadwordAtomicsABI">>;
def mvsx : Flag<["-"], "mvsx">, Group<m_ppc_Features_Group>;
def mno_vsx : Flag<["-"], "mno-vsx">, Group<m_ppc_Features_Group>;
def msecure_plt : Flag<["-"], "msecure-plt">, Group<m_ppc_Features_Group>;

View File

@ -107,10 +107,10 @@ class DependencyFileGenerator : public DependencyCollector {
void finishedMainFile(DiagnosticsEngine &Diags) override;
bool needSystemDependencies() final override { return IncludeSystemHeaders; }
bool needSystemDependencies() final { return IncludeSystemHeaders; }
bool sawDependency(StringRef Filename, bool FromModule, bool IsSystem,
bool IsModuleFile, bool IsMissing) final override;
bool IsModuleFile, bool IsMissing) final;
protected:
void outputDependencyFile(llvm::raw_ostream &OS);

View File

@ -49,7 +49,6 @@ void operator delete(void *ptr, clang::PreprocessingRecord &PR,
namespace clang {
class FileEntry;
class IdentifierInfo;
class MacroInfo;
class SourceManager;

View File

@ -67,7 +67,6 @@ namespace clang {
class CodeCompletionHandler;
class CommentHandler;
class DirectoryEntry;
class DirectoryLookup;
class EmptylineHandler;
class ExternalPreprocessorSource;
class FileEntry;

View File

@ -215,6 +215,7 @@ class Parser : public CodeCompletionHandler {
std::unique_ptr<PragmaHandler> AttributePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
std::unique_ptr<CommentHandler> CommentSemaHandler;
@ -1043,7 +1044,7 @@ class Parser : public CodeCompletionHandler {
/// If the next token is not a semicolon, this emits the specified diagnostic,
/// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior
/// to the semicolon, consumes that extra token.
bool ExpectAndConsumeSemi(unsigned DiagID);
bool ExpectAndConsumeSemi(unsigned DiagID , StringRef TokenUsed = "");
/// The kind of extra semi diagnostic to emit.
enum ExtraSemiKind {

View File

@ -795,6 +795,10 @@ class Sema;
/// This candidate was not viable because its associated constraints were
/// not satisfied.
ovl_fail_constraints_not_satisfied,
/// This candidate was not viable because it has internal linkage and is
/// from a different module unit than the use.
ovl_fail_module_mismatched,
};
/// A list of implicit conversion sequences for the arguments of an

View File

@ -0,0 +1,36 @@
//===- RISCVIntrinsicManager.h - RISC-V Intrinsic Handler -------*- 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 the RISCVIntrinsicManager, which handles RISC-V vector
// intrinsic functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
#define LLVM_CLANG_SEMA_RISCVINTRINSICMANAGER_H
namespace clang {
class Sema;
class LookupResult;
class IdentifierInfo;
class Preprocessor;
namespace sema {
class RISCVIntrinsicManager {
public:
virtual ~RISCVIntrinsicManager() = default;
// Create RISC-V intrinsic and insert into symbol table and return true if
// found, otherwise return false.
virtual bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
Preprocessor &PP) = 0;
};
} // end namespace sema
} // end namespace clang
#endif

View File

@ -210,9 +210,19 @@ class Scope {
/// Used to determine if errors occurred in this scope.
DiagnosticErrorTrap ErrorTrap;
/// A lattice consisting of undefined, a single NRVO candidate variable in
/// this scope, or over-defined. The bit is true when over-defined.
llvm::PointerIntPair<VarDecl *, 1, bool> NRVO;
/// A single NRVO candidate variable in this scope.
/// There are three possible values:
/// 1) pointer to VarDecl that denotes NRVO candidate itself.
/// 2) nullptr value means that NRVO is not allowed in this scope
/// (e.g. return a function parameter).
/// 3) None value means that there is no NRVO candidate in this scope
/// (i.e. there are no return statements in this scope).
Optional<VarDecl *> NRVO;
/// Represents return slots for NRVO candidates in the current scope.
/// If a variable is present in this set, it means that a return slot is
/// available for this variable in the current scope.
llvm::SmallPtrSet<VarDecl *, 8> ReturnSlots;
void setFlags(Scope *Parent, unsigned F);
@ -304,6 +314,10 @@ class Scope {
bool decl_empty() const { return DeclsInScope.empty(); }
void AddDecl(Decl *D) {
if (auto *VD = dyn_cast<VarDecl>(D))
if (!isa<ParmVarDecl>(VD))
ReturnSlots.insert(VD);
DeclsInScope.insert(D);
}
@ -527,23 +541,9 @@ class Scope {
UsingDirectives.end());
}
void addNRVOCandidate(VarDecl *VD) {
if (NRVO.getInt())
return;
if (NRVO.getPointer() == nullptr) {
NRVO.setPointer(VD);
return;
}
if (NRVO.getPointer() != VD)
setNoNRVO();
}
void updateNRVOCandidate(VarDecl *VD);
void setNoNRVO() {
NRVO.setInt(true);
NRVO.setPointer(nullptr);
}
void mergeNRVOIntoParent();
void applyNRVO();
/// Init - This is used by the parser to implement scope caching.
void Init(Scope *parent, unsigned flags);

View File

@ -226,6 +226,7 @@ namespace sema {
class FunctionScopeInfo;
class LambdaScopeInfo;
class PossiblyUnreachableDiag;
class RISCVIntrinsicManager;
class SemaPPCallbacks;
class TemplateDeductionInfo;
}
@ -1587,7 +1588,12 @@ class Sema final {
/// assignment.
llvm::DenseMap<const VarDecl *, int> RefsMinusAssignments;
/// Indicate RISC-V vector builtin functions enabled or not.
bool DeclareRISCVVBuiltins = false;
private:
std::unique_ptr<sema::RISCVIntrinsicManager> RVIntrinsicManager;
Optional<std::unique_ptr<DarwinSDKInfo>> CachedDarwinSDKInfo;
bool WarnedDarwinSDKInfoMissing = false;
@ -8260,6 +8266,9 @@ class Sema final {
Scope *S, MultiTemplateParamsArg TemplateParameterLists,
IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr);
void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
bool &AddToScope);
RequiresExprBodyDecl *
ActOnStartRequiresExpr(SourceLocation RequiresKWLoc,
ArrayRef<ParmVarDecl *> LocalParameters,
@ -12170,7 +12179,8 @@ class Sema final {
// For simple assignment, pass both expressions and a null converted type.
// For compound assignment, pass both expressions and the converted type.
QualType CheckAssignmentOperands( // C99 6.5.16.[1,2]
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType);
Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType,
BinaryOperatorKind Opc);
ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc,
UnaryOperatorKind Opcode, Expr *Op);
@ -13586,6 +13596,8 @@ void Sema::PragmaStack<Sema::AlignPackInfo>::Act(SourceLocation PragmaLocation,
llvm::StringRef StackSlotLabel,
AlignPackInfo Value);
std::unique_ptr<sema::RISCVIntrinsicManager>
CreateRISCVIntrinsicManager(Sema &S);
} // end namespace clang
namespace llvm {

View File

@ -75,6 +75,8 @@ enum class TemplateSubstitutionKind : char {
class MultiLevelTemplateArgumentList {
/// The template argument list at a certain template depth
using ArgList = ArrayRef<TemplateArgument>;
using ArgListsIterator = SmallVector<ArgList, 4>::iterator;
using ConstArgListsIterator = SmallVector<ArgList, 4>::const_iterator;
/// The template argument lists, stored from the innermost template
/// argument list (first) to the outermost template argument list (last).
@ -121,6 +123,12 @@ enum class TemplateSubstitutionKind : char {
return TemplateArgumentLists.size();
}
// Determine the number of substituted args at 'Depth'.
unsigned getNumSubsitutedArgs(unsigned Depth) const {
assert(NumRetainedOuterLevels <= Depth && Depth < getNumLevels());
return TemplateArgumentLists[getNumLevels() - Depth - 1].size();
}
unsigned getNumRetainedOuterLevels() const {
return NumRetainedOuterLevels;
}
@ -158,6 +166,14 @@ enum class TemplateSubstitutionKind : char {
return !(*this)(Depth, Index).isNull();
}
bool isAnyArgInstantiationDependent() const {
for (ArgList List : TemplateArgumentLists)
for (const TemplateArgument &TA : List)
if (TA.isInstantiationDependent())
return true;
return false;
}
/// Clear out a specific template argument.
void setArgument(unsigned Depth, unsigned Index,
TemplateArgument Arg) {
@ -183,6 +199,14 @@ enum class TemplateSubstitutionKind : char {
TemplateArgumentLists.push_back(Args);
}
/// Replaces the current 'innermost' level with the provided argument list.
/// This is useful for type deduction cases where we need to get the entire
/// list from the AST, but then add the deduced innermost list.
void replaceInnermostTemplateArguments(ArgList Args) {
assert(TemplateArgumentLists.size() > 0 && "Replacing in an empty list?");
TemplateArgumentLists[0] = Args;
}
/// Add an outermost level that we are not substituting. We have no
/// arguments at this level, and do not remove it from the depth of inner
/// template parameters that we instantiate.
@ -197,6 +221,16 @@ enum class TemplateSubstitutionKind : char {
const ArgList &getInnermost() const {
return TemplateArgumentLists.front();
}
/// Retrieve the outermost template argument list.
const ArgList &getOutermost() const {
return TemplateArgumentLists.back();
}
ArgListsIterator begin() { return TemplateArgumentLists.begin(); }
ConstArgListsIterator begin() const {
return TemplateArgumentLists.begin();
}
ArgListsIterator end() { return TemplateArgumentLists.end(); }
ConstArgListsIterator end() const { return TemplateArgumentLists.end(); }
};
/// The context in which partial ordering of function templates occurs.

View File

@ -703,6 +703,10 @@ class ASTWriter : public ASTDeserializationListener,
bool hasChain() const { return Chain; }
ASTReader *getChain() const { return Chain; }
bool isWritingNamedModules() const {
return WritingModule && WritingModule->isModulePurview();
}
private:
// ASTDeserializationListener implementation
void ReaderInitialized(ASTReader *Reader) override;

View File

@ -731,7 +731,7 @@ class NoStateChangeFuncVisitor : public BugReporterVisitor {
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BR,
PathSensitiveBugReport &R) override final;
PathSensitiveBugReport &R) final;
};
} // namespace ento

View File

@ -622,6 +622,11 @@ class ExprEngine {
getIndexOfElementToConstruct(ProgramStateRef State, const CXXConstructExpr *E,
const LocationContext *LCtx);
/// Retreives the size of the array in the pending ArrayInitLoopExpr.
static Optional<unsigned> getPendingInitLoop(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.
@ -816,7 +821,9 @@ class ExprEngine {
/// Checks whether our policies allow us to inline a non-POD type array
/// construction.
bool shouldInlineArrayConstruction(const ArrayType *Type);
bool shouldInlineArrayConstruction(const ProgramStateRef State,
const CXXConstructExpr *CE,
const LocationContext *LCtx);
/// Checks whether we construct an array of non-POD type, and decides if the
/// constructor should be inkoved once again.
@ -916,6 +923,16 @@ class ExprEngine {
const CXXConstructExpr *E,
const LocationContext *LCtx);
/// Sets the size of the array in a pending ArrayInitLoopExpr.
static ProgramStateRef setPendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx,
unsigned Idx);
static ProgramStateRef removePendingInitLoop(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

View File

@ -55,8 +55,6 @@ template <typename T> struct ProgramStateTrait {
}
};
class RangeSet;
/// \class ProgramState
/// ProgramState - This class encapsulates:
///

View File

@ -40,7 +40,6 @@ class LabelDecl;
namespace ento {
class BasicValueFactory;
class CompoundValData;
class LazyCompoundValData;
class MemRegion;

View File

@ -18,6 +18,10 @@
#include <string>
#include <vector>
namespace llvm {
class raw_ostream;
} // end namespace llvm
namespace clang {
namespace RISCV {
@ -104,12 +108,14 @@ struct PrototypeDescriptor {
uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
bool operator!=(const PrototypeDescriptor &PD) const {
return PD.PT != PT || PD.VTM != VTM || PD.TM != TM;
return !(*this == PD);
}
bool operator>(const PrototypeDescriptor &PD) const {
return !(PD.PT <= PT && PD.VTM <= VTM && PD.TM <= TM);
bool operator==(const PrototypeDescriptor &PD) const {
return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
}
bool operator<(const PrototypeDescriptor &PD) const {
return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
}
static const PrototypeDescriptor Mask;
static const PrototypeDescriptor Vector;
static const PrototypeDescriptor VL;
@ -224,8 +230,12 @@ class RVVType {
bool isFloat(unsigned Width) const {
return isFloat() && ElementBitwidth == Width;
}
bool isConstant() const { return IsConstant; }
bool isPointer() const { return IsPointer; }
unsigned getElementBitwidth() const { return ElementBitwidth; }
ScalarTypeKind getScalarType() const { return ScalarType; }
VScaleVal getScale() const { return Scale; }
private:
// Verify RVV vector type and set Valid.
@ -263,18 +273,6 @@ class RVVType {
PrototypeDescriptor Proto);
};
using RISCVPredefinedMacroT = uint8_t;
enum RISCVPredefinedMacro : RISCVPredefinedMacroT {
Basic = 0,
V = 1 << 1,
Zvfh = 1 << 2,
RV64 = 1 << 3,
VectorMaxELen64 = 1 << 4,
VectorMaxELenFp32 = 1 << 5,
VectorMaxELenFp64 = 1 << 6,
};
enum PolicyScheme : uint8_t {
SchemeNone,
HasPassthruOperand,
@ -302,7 +300,6 @@ class RVVIntrinsic {
// The types we use to obtain the specific LLVM intrinsic. They are index of
// InputTypes. -1 means the return type.
std::vector<int64_t> IntrinsicTypes;
RISCVPredefinedMacroT RISCVPredefinedMacros = 0;
unsigned NF = 1;
public:
@ -333,9 +330,6 @@ class RVVIntrinsic {
llvm::StringRef getIRName() const { return IRName; }
llvm::StringRef getManualCodegen() const { return ManualCodegen; }
PolicyScheme getPolicyScheme() const { return Scheme; }
RISCVPredefinedMacroT getRISCVPredefinedMacros() const {
return RISCVPredefinedMacros;
}
unsigned getNF() const { return NF; }
const std::vector<int64_t> &getIntrinsicTypes() const {
return IntrinsicTypes;
@ -347,8 +341,72 @@ class RVVIntrinsic {
static std::string
getSuffixStr(BasicType Type, int Log2LMUL,
llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
static llvm::SmallVector<PrototypeDescriptor>
computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
unsigned NF);
};
// RVVRequire should be sync'ed with target features, but only
// required features used in riscv_vector.td.
enum RVVRequire : uint8_t {
RVV_REQ_None = 0,
RVV_REQ_RV64 = 1 << 0,
RVV_REQ_FullMultiply = 1 << 1,
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_FullMultiply)
};
// Raw RVV intrinsic info, used to expand later.
// This struct is highly compact for minimized code size.
struct RVVIntrinsicRecord {
// Intrinsic name, e.g. vadd_vv
const char *Name;
// Overloaded intrinsic name, could be empty if it can be computed from Name.
// e.g. vadd
const char *OverloadedName;
// Prototype for this intrinsic, index of RVVSignatureTable.
uint16_t PrototypeIndex;
// Suffix of intrinsic name, index of RVVSignatureTable.
uint16_t SuffixIndex;
// Suffix of overloaded intrinsic name, index of RVVSignatureTable.
uint16_t OverloadedSuffixIndex;
// Length of the prototype.
uint8_t PrototypeLength;
// Length of intrinsic name suffix.
uint8_t SuffixLength;
// Length of overloaded intrinsic suffix.
uint8_t OverloadedSuffixSize;
// Required target features for this intrinsic.
uint8_t RequiredExtensions;
// Supported type, mask of BasicType.
uint8_t TypeRangeMask;
// Supported LMUL.
uint8_t Log2LMULMask;
// Number of fields, greater than 1 if it's segment load/store.
uint8_t NF;
bool HasMasked : 1;
bool HasVL : 1;
bool HasMaskedOffOperand : 1;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
const RVVIntrinsicRecord &RVVInstrRecord);
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
} // end namespace RISCV
} // end namespace clang

View File

@ -98,7 +98,7 @@ class OptionRequirement : public RefactoringOptionsRequirement {
OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
ArrayRef<std::shared_ptr<RefactoringOption>>
getRefactoringOptions() const final override {
getRefactoringOptions() const final {
return Opt;
}

View File

@ -52,7 +52,7 @@ using RefactoringActionRules =
class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
public:
void invoke(RefactoringResultConsumer &Consumer,
RefactoringRuleContext &Context) final override {
RefactoringRuleContext &Context) final {
Expected<AtomicChanges> Changes = createSourceReplacements(Context);
if (!Changes)
Consumer.handleError(Changes.takeError());
@ -74,7 +74,7 @@ class SourceChangeRefactoringRule : public RefactoringActionRuleBase {
class FindSymbolOccurrencesRefactoringRule : public RefactoringActionRuleBase {
public:
void invoke(RefactoringResultConsumer &Consumer,
RefactoringRuleContext &Context) final override {
RefactoringRuleContext &Context) final {
Expected<SymbolOccurrences> Occurrences = findSymbolOccurrences(Context);
if (!Occurrences)
Consumer.handleError(Occurrences.takeError());

View File

@ -24,7 +24,7 @@ template <typename T,
typename = std::enable_if_t<traits::IsValidOptionType<T>::value>>
class OptionalRefactoringOption : public RefactoringOption {
public:
void passToVisitor(RefactoringOptionVisitor &Visitor) final override {
void passToVisitor(RefactoringOptionVisitor &Visitor) final {
Visitor.visit(*this, Value);
}
@ -48,7 +48,7 @@ class RequiredRefactoringOption : public OptionalRefactoringOption<T> {
const ValueType &getValue() const {
return *OptionalRefactoringOption<T>::Value;
}
bool isRequired() const final override { return true; }
bool isRequired() const final { return true; }
};
} // end namespace tooling

View File

@ -12,9 +12,9 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTImporterSharedState.h"
#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
@ -34,6 +34,7 @@
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@ -58,8 +59,8 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@ -3219,9 +3220,12 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD,
}
// Returns true if the given D has a DeclContext up to the TranslationUnitDecl
// which is equal to the given DC.
// which is equal to the given DC, or D is equal to DC.
static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
const DeclContext *DCi = D->getDeclContext();
const DeclContext *DCi = dyn_cast<DeclContext>(D);
if (!DCi)
DCi = D->getDeclContext();
assert(DCi && "Declaration should have a context");
while (DCi != D->getTranslationUnitDecl()) {
if (DCi == DC)
return true;
@ -3230,9 +3234,36 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
return false;
}
// Returns true if the statement S has a parent declaration that has a
// DeclContext that is inside (or equal to) DC. In a specific use case if DC is
// a FunctionDecl, check if statement S resides in the body of the function.
static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext();
DynTypedNodeList Parents = ParentC.getParents(*S);
while (!Parents.empty()) {
if (const Decl *PD = Parents.begin()->get<Decl>())
return isAncestorDeclContextOf(DC, PD);
Parents = ParentC.getParents(*Parents.begin());
}
return false;
}
static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
if (T.isNull())
return false;
auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) {
switch (Arg.getKind()) {
case TemplateArgument::Type:
return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD);
case TemplateArgument::Expression:
return isAncestorDeclContextOf(FD, Arg.getAsExpr());
default:
// FIXME: Handle other argument kinds.
return false;
}
};
if (const auto *RecordT = T->getAs<RecordType>()) {
const RecordDecl *RD = RecordT->getDecl();
assert(RD);
@ -3241,12 +3272,15 @@ static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
return true;
}
if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
return llvm::count_if(RDTempl->getTemplateArgs().asArray(),
[FD](const TemplateArgument &Arg) {
return hasTypeDeclaredInsideFunction(
Arg.getAsType(), FD);
});
if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
CheckTemplateArgument))
return true;
// Note: It is possible that T can be get as both a RecordType and a
// TemplateSpecializationType.
}
if (const auto *TST = T->getAs<TemplateSpecializationType>())
return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
return false;
}

View File

@ -394,7 +394,6 @@ void LinkageComputer::mergeTemplateLV(
shouldConsiderTemplateVisibility(fn, specInfo);
FunctionTemplateDecl *temp = specInfo->getTemplate();
// Merge information from the template declaration.
LinkageInfo tempLV = getLVForDecl(temp, computation);
// The linkage of the specialization should be consistent with the
@ -468,11 +467,16 @@ void LinkageComputer::mergeTemplateLV(
// Merge information from the template parameters, but ignore
// visibility if we're only considering template arguments.
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
// Merge information from the template declaration.
LinkageInfo tempLV = getLVForDecl(temp, computation);
// The linkage of the specialization should be consistent with the
// template declaration.
LV.setLinkage(tempLV.getLinkage());
LinkageInfo paramsLV =
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV,
LV.mergeMaybeWithVisibility(paramsLV,
considerVisibility && !hasExplicitVisibilityAlready(computation));
// Merge information from the template arguments. We ignore
@ -520,7 +524,6 @@ void LinkageComputer::mergeTemplateLV(LinkageInfo &LV,
// Merge information from the template parameters, but ignore
// visibility if we're only considering template arguments.
VarTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
@ -1077,7 +1080,6 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// Finally, merge in information from the class.
LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
return LV;
}

View File

@ -5269,10 +5269,14 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
}
bool Cond;
if (IS->isConsteval())
if (IS->isConsteval()) {
Cond = IS->isNonNegatedConsteval();
else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
Cond))
// If we are not in a constant context, if consteval should not evaluate
// to true.
if (!Info.InConstantContext)
Cond = !Cond;
} else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(),
Cond))
return ESR_Failed;
if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {

View File

@ -1659,9 +1659,13 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
appendInitializer(Block, I);
if (Init) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
Init);
AILE ? AILE->getSubExpr() : Init);
if (HasTemporaries) {
// For expression with temporaries go directly to subexpression to omit
@ -2928,12 +2932,30 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) {
}
}
// If we bind to a tuple-like type, we iterate over the HoldingVars, and
// create a DeclStmt for each of them.
if (const auto *DD = dyn_cast<DecompositionDecl>(VD)) {
for (auto BD : llvm::reverse(DD->bindings())) {
if (auto *VD = BD->getHoldingVar()) {
DeclGroupRef DG(VD);
DeclStmt *DSNew =
new (Context) DeclStmt(DG, VD->getLocation(), GetEndLoc(VD));
cfg->addSyntheticDeclStmt(DSNew, DS);
Block = VisitDeclSubExpr(DSNew);
}
}
}
autoCreateBlock();
appendStmt(Block, DS);
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
findConstructionContexts(
ConstructionContextLayer::create(cfg->getBumpVectorContext(), DS),
Init);
AILE ? AILE->getSubExpr() : Init);
// Keep track of the last non-null block, as 'Block' can be nulled out
// if the initializer expression is something like a 'while' in a
@ -3340,9 +3362,20 @@ CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) {
CFGBlock *CFGBuilder::VisitLambdaExpr(LambdaExpr *E, AddStmtChoice asc) {
CFGBlock *LastBlock = VisitNoRecurse(E, asc);
unsigned Idx = 0;
for (LambdaExpr::capture_init_iterator it = E->capture_init_begin(),
et = E->capture_init_end(); it != et; ++it) {
et = E->capture_init_end();
it != et; ++it, ++Idx) {
if (Expr *Init = *it) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init);
findConstructionContexts(ConstructionContextLayer::create(
cfg->getBumpVectorContext(), {E, Idx}),
AILE ? AILE->getSubExpr() : Init);
CFGBlock *Tmp = Visit(Init);
if (Tmp)
LastBlock = Tmp;
@ -5616,6 +5649,12 @@ static void print_construction_context(raw_ostream &OS,
Stmts.push_back(TOCC->getConstructorAfterElision());
break;
}
case ConstructionContext::LambdaCaptureKind: {
const auto *LCC = cast<LambdaCaptureConstructionContext>(CC);
Helper.handledStmt(const_cast<LambdaExpr *>(LCC->getLambdaExpr()), OS);
OS << "+" << LCC->getIndex();
return;
}
case ConstructionContext::ArgumentKind: {
const auto *ACC = cast<ArgumentConstructionContext>(CC);
if (const Stmt *BTE = ACC->getCXXBindTemporaryExpr()) {

View File

@ -156,6 +156,12 @@ const ConstructionContext *ConstructionContext::createBoundTemporaryFromLayers(
return create<CXX17ElidedCopyConstructorInitializerConstructionContext>(
C, I, BTE);
}
case ConstructionContextItem::LambdaCaptureKind: {
assert(ParentLayer->isLast());
const auto *E = cast<LambdaExpr>(ParentItem.getStmt());
return create<LambdaCaptureConstructionContext>(C, E,
ParentItem.getIndex());
}
} // switch (ParentItem.getKind())
llvm_unreachable("Unexpected construction context with destructor!");
@ -200,6 +206,11 @@ const ConstructionContext *ConstructionContext::createFromLayers(
case ConstructionContextItem::ElidableConstructorKind: {
llvm_unreachable("The argument needs to be materialized first!");
}
case ConstructionContextItem::LambdaCaptureKind: {
assert(TopLayer->isLast());
const auto *E = cast<LambdaExpr>(TopItem.getStmt());
return create<LambdaCaptureConstructionContext>(C, E, TopItem.getIndex());
}
case ConstructionContextItem::InitializerKind: {
assert(TopLayer->isLast());
const CXXCtorInitializer *I = TopItem.getCXXCtorInitializer();

View File

@ -455,14 +455,16 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
// array is considered modified if the loop-variable is a non-const reference.
const auto DeclStmtToNonRefToArray = declStmt(hasSingleDecl(varDecl(hasType(
hasUnqualifiedDesugaredType(referenceType(pointee(arrayType())))))));
const auto RefToArrayRefToElements = match(
findAll(stmt(cxxForRangeStmt(
hasLoopVariable(varDecl(hasType(nonConstReferenceType()))
.bind(NodeID<Decl>::value)),
hasRangeStmt(DeclStmtToNonRefToArray),
hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
.bind("stmt")),
Stm, Context);
const auto RefToArrayRefToElements =
match(findAll(stmt(cxxForRangeStmt(
hasLoopVariable(
varDecl(anyOf(hasType(nonConstReferenceType()),
hasType(nonConstPointerType())))
.bind(NodeID<Decl>::value)),
hasRangeStmt(DeclStmtToNonRefToArray),
hasRangeInit(canResolveToExpr(equalsNode(Exp)))))
.bind("stmt")),
Stm, Context);
if (const auto *BadRangeInitFromArray =
selectFirst<Stmt>("stmt", RefToArrayRefToElements))

View File

@ -113,16 +113,27 @@ BoolValue &DataflowAnalysisContext::getOrCreateNegation(BoolValue &Val) {
BoolValue &DataflowAnalysisContext::getOrCreateImplication(BoolValue &LHS,
BoolValue &RHS) {
return &LHS == &RHS ? getBoolLiteralValue(true)
: getOrCreateDisjunction(getOrCreateNegation(LHS), RHS);
if (&LHS == &RHS)
return getBoolLiteralValue(true);
auto Res = ImplicationVals.try_emplace(std::make_pair(&LHS, &RHS), nullptr);
if (Res.second)
Res.first->second =
&takeOwnership(std::make_unique<ImplicationValue>(LHS, RHS));
return *Res.first->second;
}
BoolValue &DataflowAnalysisContext::getOrCreateIff(BoolValue &LHS,
BoolValue &RHS) {
return &LHS == &RHS
? getBoolLiteralValue(true)
: getOrCreateConjunction(getOrCreateImplication(LHS, RHS),
getOrCreateImplication(RHS, LHS));
if (&LHS == &RHS)
return getBoolLiteralValue(true);
auto Res = BiconditionalVals.try_emplace(makeCanonicalBoolValuePair(LHS, RHS),
nullptr);
if (Res.second)
Res.first->second =
&takeOwnership(std::make_unique<BiconditionalValue>(LHS, RHS));
return *Res.first->second;
}
AtomicBoolValue &DataflowAnalysisContext::makeFlowConditionToken() {
@ -199,18 +210,18 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
if (!Res.second)
return;
auto ConstraintsIT = FlowConditionConstraints.find(&Token);
if (ConstraintsIT == FlowConditionConstraints.end()) {
auto ConstraintsIt = FlowConditionConstraints.find(&Token);
if (ConstraintsIt == FlowConditionConstraints.end()) {
Constraints.insert(&Token);
} else {
// Bind flow condition token via `iff` to its set of constraints:
// FC <=> (C1 ^ C2 ^ ...), where Ci are constraints
Constraints.insert(&getOrCreateIff(Token, *ConstraintsIT->second));
Constraints.insert(&getOrCreateIff(Token, *ConstraintsIt->second));
}
auto DepsIT = FlowConditionDeps.find(&Token);
if (DepsIT != FlowConditionDeps.end()) {
for (AtomicBoolValue *DepToken : DepsIT->second) {
auto DepsIt = FlowConditionDeps.find(&Token);
if (DepsIt != FlowConditionDeps.end()) {
for (AtomicBoolValue *DepToken : DepsIt->second) {
addTransitiveFlowConditionConstraints(*DepToken, Constraints,
VisitedTokens);
}
@ -220,10 +231,10 @@ void DataflowAnalysisContext::addTransitiveFlowConditionConstraints(
BoolValue &DataflowAnalysisContext::substituteBoolValue(
BoolValue &Val,
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
auto IT = SubstitutionsCache.find(&Val);
if (IT != SubstitutionsCache.end()) {
auto It = SubstitutionsCache.find(&Val);
if (It != SubstitutionsCache.end()) {
// Return memoized result of substituting this boolean value.
return *IT->second;
return *It->second;
}
// Handle substitution on the boolean value (and its subvalues), saving the
@ -258,6 +269,24 @@ BoolValue &DataflowAnalysisContext::substituteBoolValue(
Result = &getOrCreateConjunction(LeftSub, RightSub);
break;
}
case Value::Kind::Implication: {
auto &IV = *cast<ImplicationValue>(&Val);
auto &LeftSub =
substituteBoolValue(IV.getLeftSubValue(), SubstitutionsCache);
auto &RightSub =
substituteBoolValue(IV.getRightSubValue(), SubstitutionsCache);
Result = &getOrCreateImplication(LeftSub, RightSub);
break;
}
case Value::Kind::Biconditional: {
auto &BV = *cast<BiconditionalValue>(&Val);
auto &LeftSub =
substituteBoolValue(BV.getLeftSubValue(), SubstitutionsCache);
auto &RightSub =
substituteBoolValue(BV.getRightSubValue(), SubstitutionsCache);
Result = &getOrCreateIff(LeftSub, RightSub);
break;
}
default:
llvm_unreachable("Unhandled Value Kind");
}
@ -280,19 +309,19 @@ BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowCondition(
BoolValue &DataflowAnalysisContext::buildAndSubstituteFlowConditionWithCache(
AtomicBoolValue &Token,
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache) {
auto ConstraintsIT = FlowConditionConstraints.find(&Token);
if (ConstraintsIT == FlowConditionConstraints.end()) {
auto ConstraintsIt = FlowConditionConstraints.find(&Token);
if (ConstraintsIt == FlowConditionConstraints.end()) {
return getBoolLiteralValue(true);
}
auto DepsIT = FlowConditionDeps.find(&Token);
if (DepsIT != FlowConditionDeps.end()) {
for (AtomicBoolValue *DepToken : DepsIT->second) {
auto DepsIt = FlowConditionDeps.find(&Token);
if (DepsIt != FlowConditionDeps.end()) {
for (AtomicBoolValue *DepToken : DepsIt->second) {
auto &NewDep = buildAndSubstituteFlowConditionWithCache(
*DepToken, SubstitutionsCache);
SubstitutionsCache[DepToken] = &NewDep;
}
}
return substituteBoolValue(*ConstraintsIT->second, SubstitutionsCache);
return substituteBoolValue(*ConstraintsIt->second, SubstitutionsCache);
}
void DataflowAnalysisContext::dumpFlowCondition(AtomicBoolValue &Token) {

View File

@ -200,6 +200,42 @@ Environment::Environment(DataflowAnalysisContext &DACtx,
}
}
Environment Environment::pushCall(const CallExpr *Call) const {
Environment Env(*this);
// FIXME: Currently this only works if the callee is never a method and the
// same callee is never analyzed from multiple separate callsites. To
// generalize this, we'll need to store a "context" field (probably a stack of
// `const CallExpr *`s) in the `Environment`, and then change the
// `DataflowAnalysisContext` class to hold a map from contexts to "frames",
// where each frame stores its own version of what are currently the
// `DeclToLoc`, `ExprToLoc`, and `ThisPointeeLoc` fields.
const auto *FuncDecl = Call->getDirectCallee();
assert(FuncDecl != nullptr);
assert(FuncDecl->getBody() != nullptr);
// FIXME: In order to allow the callee to reference globals, we probably need
// to call `initGlobalVars` here in some way.
auto ParamIt = FuncDecl->param_begin();
auto ArgIt = Call->arg_begin();
auto ArgEnd = Call->arg_end();
// FIXME: Parameters don't always map to arguments 1:1; examples include
// overloaded operators implemented as member functions, and parameter packs.
for (; ArgIt != ArgEnd; ++ParamIt, ++ArgIt) {
assert(ParamIt != FuncDecl->param_end());
const VarDecl *Param = *ParamIt;
const Expr *Arg = *ArgIt;
auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
assert(ArgLoc != nullptr);
Env.setStorageLocation(*Param, *ArgLoc);
}
return Env;
}
bool Environment::equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const {
assert(DACtx == Other.DACtx);
@ -352,16 +388,16 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
}
}
auto IT = MemberLocToStruct.find(&Loc);
if (IT != MemberLocToStruct.end()) {
auto It = MemberLocToStruct.find(&Loc);
if (It != MemberLocToStruct.end()) {
// `Loc` is the location of a struct member so we need to also update the
// value of the member in the corresponding `StructValue`.
assert(IT->second.first != nullptr);
StructValue &StructVal = *IT->second.first;
assert(It->second.first != nullptr);
StructValue &StructVal = *It->second.first;
assert(IT->second.second != nullptr);
const ValueDecl &Member = *IT->second.second;
assert(It->second.second != nullptr);
const ValueDecl &Member = *It->second.second;
StructVal.setChild(Member, Val);
}

View File

@ -96,6 +96,20 @@ class DebugStringGenerator {
S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
break;
}
case Value::Kind::Implication: {
auto &IV = cast<ImplicationValue>(B);
auto L = debugString(IV.getLeftSubValue(), Depth + 1);
auto R = debugString(IV.getRightSubValue(), Depth + 1);
S = formatv("(=>\n{0}\n{1})", L, R);
break;
}
case Value::Kind::Biconditional: {
auto &BV = cast<BiconditionalValue>(B);
auto L = debugString(BV.getLeftSubValue(), Depth + 1);
auto R = debugString(BV.getRightSubValue(), Depth + 1);
S = formatv("(=\n{0}\n{1})", L, R);
break;
}
default:
llvm_unreachable("Unhandled value kind");
}

View File

@ -20,7 +20,9 @@
#include "clang/AST/OperationKinds.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
#include "clang/Analysis/FlowSensitive/Value.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/OperatorKinds.h"
@ -46,8 +48,9 @@ static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
public:
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
: StmtToEnv(StmtToEnv), Env(Env) {}
TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
TransferOptions Options)
: StmtToEnv(StmtToEnv), Env(Env), Options(Options) {}
void VisitBinaryOperator(const BinaryOperator *S) {
const Expr *LHS = S->getLHS();
@ -503,6 +506,35 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
if (ArgLoc == nullptr)
return;
Env.setStorageLocation(*S, *ArgLoc);
} else if (const FunctionDecl *F = S->getDirectCallee()) {
// This case is for context-sensitive analysis, which we only do if we
// have the callee body available in the translation unit.
if (!Options.ContextSensitive || F->getBody() == nullptr)
return;
auto &ASTCtx = F->getASTContext();
// FIXME: Cache these CFGs.
auto CFCtx = ControlFlowContext::build(F, F->getBody(), &ASTCtx);
// FIXME: Handle errors here and below.
assert(CFCtx);
auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
auto CalleeEnv = Env.pushCall(S);
// FIXME: Use the same analysis as the caller for the callee.
DataflowAnalysisOptions Options;
auto Analysis = NoopAnalysis(ASTCtx, Options);
auto BlockToOutputState =
dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
assert(BlockToOutputState);
assert(ExitBlock < BlockToOutputState->size());
auto ExitState = (*BlockToOutputState)[ExitBlock];
assert(ExitState);
Env = ExitState->Env;
}
}
@ -564,11 +596,11 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(Loc, *Val);
if (Type->isStructureOrClassType()) {
for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
const FieldDecl *Field = std::get<0>(IT);
for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
const FieldDecl *Field = std::get<0>(It);
assert(Field != nullptr);
const Expr *Init = std::get<1>(IT);
const Expr *Init = std::get<1>(It);
assert(Init != nullptr);
if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
@ -633,10 +665,12 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
const StmtToEnvMap &StmtToEnv;
Environment &Env;
TransferOptions Options;
};
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
TransferVisitor(StmtToEnv, Env).Visit(&S);
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
TransferOptions Options) {
TransferVisitor(StmtToEnv, Env, Options).Visit(&S);
}
} // namespace dataflow

View File

@ -47,9 +47,9 @@ class StmtToEnvMapImpl : public StmtToEnvMap {
: CFCtx(CFCtx), BlockToState(BlockToState) {}
const Environment *getEnvironment(const Stmt &S) const override {
auto BlockIT = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
assert(BlockIT != CFCtx.getStmtToBlock().end());
const auto &State = BlockToState[BlockIT->getSecond()->getBlockID()];
auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));
assert(BlockIt != CFCtx.getStmtToBlock().end());
const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];
assert(State);
return &State.value().Env;
}
@ -74,8 +74,9 @@ static int blockIndexInPredecessor(const CFGBlock &Pred,
class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
public:
TerminatorVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,
int BlockSuccIdx)
: StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {}
int BlockSuccIdx, TransferOptions TransferOpts)
: StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx),
TransferOpts(TransferOpts) {}
void VisitIfStmt(const IfStmt *S) {
auto *Cond = S->getCond();
@ -118,7 +119,7 @@ class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
void extendFlowCondition(const Expr &Cond) {
// The terminator sub-expression might not be evaluated.
if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr)
transfer(StmtToEnv, Cond, Env);
transfer(StmtToEnv, Cond, Env, TransferOpts);
// FIXME: The flow condition must be an r-value, so `SkipPast::None` should
// suffice.
@ -150,6 +151,7 @@ class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> {
const StmtToEnvMap &StmtToEnv;
Environment &Env;
int BlockSuccIdx;
TransferOptions TransferOpts;
};
/// Computes the input state for a given basic block by joining the output
@ -217,7 +219,8 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
TerminatorVisitor(StmtToEnv, PredState.Env,
blockIndexInPredecessor(*Pred, Block))
blockIndexInPredecessor(*Pred, Block),
Analysis.builtinTransferOptions())
.Visit(PredTerminatorStmt);
}
}
@ -253,7 +256,8 @@ static void transferCFGStmt(
assert(S != nullptr);
if (Analysis.applyBuiltinTransfer())
transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env);
transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env,
Analysis.builtinTransferOptions());
Analysis.transferTypeErased(S, State.Lattice, State.Env);
if (HandleTransferredStmt != nullptr)

View File

@ -221,6 +221,18 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
UnprocessedSubVals.push(&N->getSubVal());
break;
}
case Value::Kind::Implication: {
auto *I = cast<ImplicationValue>(Val);
UnprocessedSubVals.push(&I->getLeftSubValue());
UnprocessedSubVals.push(&I->getRightSubValue());
break;
}
case Value::Kind::Biconditional: {
auto *B = cast<BiconditionalValue>(Val);
UnprocessedSubVals.push(&B->getLeftSubValue());
UnprocessedSubVals.push(&B->getRightSubValue());
break;
}
case Value::Kind::AtomicBool: {
Atomics[Var] = cast<AtomicBoolValue>(Val);
break;
@ -263,30 +275,52 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
const Variable LeftSubVar = GetVar(&C->getLeftSubValue());
const Variable RightSubVar = GetVar(&C->getRightSubValue());
// `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
// which is already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar));
Formula.addClause(negLit(Var), posLit(RightSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
if (LeftSubVar == RightSubVar) {
// `X <=> (A ^ A)` is equivalent to `(!X v A) ^ (X v !A)` which is
// already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&C->getLeftSubValue());
UnprocessedSubVals.push(&C->getRightSubValue());
// Visit a sub-value of `Val` (pick any, they are identical).
UnprocessedSubVals.push(&C->getLeftSubValue());
} else {
// `X <=> (A ^ B)` is equivalent to `(!X v A) ^ (!X v B) ^ (X v !A v !B)`
// which is already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar));
Formula.addClause(negLit(Var), posLit(RightSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&C->getLeftSubValue());
UnprocessedSubVals.push(&C->getRightSubValue());
}
} else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
const Variable LeftSubVar = GetVar(&D->getLeftSubValue());
const Variable RightSubVar = GetVar(&D->getRightSubValue());
// `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
// which is already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar));
Formula.addClause(posLit(Var), negLit(RightSubVar));
if (LeftSubVar == RightSubVar) {
// `X <=> (A v A)` is equivalent to `(!X v A) ^ (X v !A)` which is
// already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&D->getLeftSubValue());
UnprocessedSubVals.push(&D->getRightSubValue());
// Visit a sub-value of `Val` (pick any, they are identical).
UnprocessedSubVals.push(&D->getLeftSubValue());
} else {
// `X <=> (A v B)` is equivalent to `(!X v A v B) ^ (X v !A) ^ (X v !B)`
// which is already in conjunctive normal form. Below we add each of the
// conjuncts of the latter expression to the result.
Formula.addClause(negLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar));
Formula.addClause(posLit(Var), negLit(RightSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&D->getLeftSubValue());
UnprocessedSubVals.push(&D->getRightSubValue());
}
} else if (auto *N = dyn_cast<NegationValue>(Val)) {
const Variable SubVar = GetVar(&N->getSubVal());
@ -298,6 +332,46 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&N->getSubVal());
} else if (auto *I = dyn_cast<ImplicationValue>(Val)) {
const Variable LeftSubVar = GetVar(&I->getLeftSubValue());
const Variable RightSubVar = GetVar(&I->getRightSubValue());
// `X <=> (A => B)` is equivalent to
// `(X v A) ^ (X v !B) ^ (!X v !A v B)` which is already in
// conjunctive normal form. Below we add each of the conjuncts of the
// latter expression to the result.
Formula.addClause(posLit(Var), posLit(LeftSubVar));
Formula.addClause(posLit(Var), negLit(RightSubVar));
Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&I->getLeftSubValue());
UnprocessedSubVals.push(&I->getRightSubValue());
} else if (auto *B = dyn_cast<BiconditionalValue>(Val)) {
const Variable LeftSubVar = GetVar(&B->getLeftSubValue());
const Variable RightSubVar = GetVar(&B->getRightSubValue());
if (LeftSubVar == RightSubVar) {
// `X <=> (A <=> A)` is equvalent to `X` which is already in
// conjunctive normal form. Below we add each of the conjuncts of the
// latter expression to the result.
Formula.addClause(posLit(Var));
// No need to visit the sub-values of `Val`.
} else {
// `X <=> (A <=> B)` is equivalent to
// `(X v A v B) ^ (X v !A v !B) ^ (!X v A v !B) ^ (!X v !A v B)` which is
// already in conjunctive normal form. Below we add each of the conjuncts
// of the latter expression to the result.
Formula.addClause(posLit(Var), posLit(LeftSubVar), posLit(RightSubVar));
Formula.addClause(posLit(Var), negLit(LeftSubVar), negLit(RightSubVar));
Formula.addClause(negLit(Var), posLit(LeftSubVar), negLit(RightSubVar));
Formula.addClause(negLit(Var), negLit(LeftSubVar), posLit(RightSubVar));
// Visit the sub-values of `Val`.
UnprocessedSubVals.push(&B->getLeftSubValue());
UnprocessedSubVals.push(&B->getRightSubValue());
}
}
}

View File

@ -72,6 +72,11 @@ bool LiveVariables::LivenessValues::isLive(const VarDecl *D) const {
bool alive = false;
for (const BindingDecl *BD : DD->bindings())
alive |= liveBindings.contains(BD);
// Note: the only known case this condition is necessary, is when a bindig
// to a tuple-like structure is created. The HoldingVar initializers have a
// DeclRefExpr to the DecompositionDecl.
alive |= liveDecls.contains(DD);
return alive;
}
return liveDecls.contains(D);
@ -343,8 +348,12 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) {
if (const BindingDecl* BD = dyn_cast<BindingDecl>(D)) {
Killed = !BD->getType()->isReferenceType();
if (Killed)
if (Killed) {
if (const auto *HV = BD->getHoldingVar())
val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
Killed = writeShouldKill(VD);
if (Killed)
@ -371,8 +380,12 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
const Decl* D = DR->getDecl();
bool InAssignment = LV.inAssignment[DR];
if (const auto *BD = dyn_cast<BindingDecl>(D)) {
if (!InAssignment)
if (!InAssignment) {
if (const auto *HV = BD->getHoldingVar())
val.liveDecls = LV.DSetFact.add(val.liveDecls, HV);
val.liveBindings = LV.BSetFact.add(val.liveBindings, BD);
}
} else if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (!InAssignment && !isAlwaysAlive(VD))
val.liveDecls = LV.DSetFact.add(val.liveDecls, VD);
@ -382,8 +395,16 @@ void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *DR) {
void TransferFunctions::VisitDeclStmt(DeclStmt *DS) {
for (const auto *DI : DS->decls()) {
if (const auto *DD = dyn_cast<DecompositionDecl>(DI)) {
for (const auto *BD : DD->bindings())
for (const auto *BD : DD->bindings()) {
if (const auto *HV = BD->getHoldingVar())
val.liveDecls = LV.DSetFact.remove(val.liveDecls, HV);
val.liveBindings = LV.BSetFact.remove(val.liveBindings, BD);
}
// When a bindig to a tuple-like structure is created, the HoldingVar
// initializers have a DeclRefExpr to the DecompositionDecl.
val.liveDecls = LV.DSetFact.remove(val.liveDecls, DD);
} else if (const auto *VD = dyn_cast<VarDecl>(DI)) {
if (!isAlwaysAlive(VD))
val.liveDecls = LV.DSetFact.remove(val.liveDecls, VD);

View File

@ -71,7 +71,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYTargetInfo : public TargetInfo {
bool isValidCPUName(StringRef Name) const override;
virtual unsigned getMinGlobalAlign(uint64_t) const override;
unsigned getMinGlobalAlign(uint64_t) const override;
ArrayRef<Builtin::Info> getTargetBuiltins() const override;

View File

@ -849,6 +849,9 @@ void PPCTargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
? &llvm::APFloat::IEEEquad()
: &llvm::APFloat::PPCDoubleDouble();
Opts.IEEE128 = 1;
if (getTriple().isOSAIX() && Opts.EnableAIXQuadwordAtomicsABI &&
HasQuadwordAtomics)
MaxAtomicInlineWidth = 128;
}
ArrayRef<Builtin::Info> PPCTargetInfo::getTargetBuiltins() const {

View File

@ -229,14 +229,14 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool validateInputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef Constraint, unsigned Size) const override;
virtual bool
bool
checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override {
if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
return true;
return TargetInfo::checkCFProtectionReturnSupported(Diags);
};
virtual bool
bool
checkCFProtectionBranchSupported(DiagnosticsEngine &Diags) const override {
if (CPU == llvm::X86::CK_None || CPU >= llvm::X86::CK_PentiumPro)
return true;

View File

@ -127,7 +127,7 @@ namespace CodeGen {
public:
SwiftABIInfo(CodeGen::CodeGenTypes &cgt) : ABIInfo(cgt) {}
bool supportsSwift() const final override { return true; }
bool supportsSwift() const final { return true; }
virtual bool shouldPassIndirectlyForSwift(ArrayRef<llvm::Type*> types,
bool asReturnValue) const = 0;

View File

@ -41,6 +41,8 @@ struct CatchTypeInfo;
/// Implements C++ ABI-specific code generation functions.
class CGCXXABI {
friend class CodeGenModule;
protected:
CodeGenModule &CGM;
std::unique_ptr<MangleContext> MangleCtx;

View File

@ -4473,17 +4473,22 @@ llvm::CallInst *CodeGenFunction::EmitRuntimeCall(llvm::FunctionCallee callee,
// they are nested within.
SmallVector<llvm::OperandBundleDef, 1>
CodeGenFunction::getBundlesForFunclet(llvm::Value *Callee) {
SmallVector<llvm::OperandBundleDef, 1> BundleList;
// There is no need for a funclet operand bundle if we aren't inside a
// funclet.
if (!CurrentFuncletPad)
return BundleList;
return (SmallVector<llvm::OperandBundleDef, 1>());
// Skip intrinsics which cannot throw.
auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts());
if (CalleeFn && CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow())
return BundleList;
// Skip intrinsics which cannot throw (as long as they don't lower into
// regular function calls in the course of IR transformations).
if (auto *CalleeFn = dyn_cast<llvm::Function>(Callee->stripPointerCasts())) {
if (CalleeFn->isIntrinsic() && CalleeFn->doesNotThrow()) {
auto IID = CalleeFn->getIntrinsicID();
if (!llvm::IntrinsicInst::mayLowerToFunctionCall(IID))
return (SmallVector<llvm::OperandBundleDef, 1>());
}
}
SmallVector<llvm::OperandBundleDef, 1> BundleList;
BundleList.emplace_back("funclet", CurrentFuncletPad);
return BundleList;
}

View File

@ -2698,15 +2698,21 @@ void CodeGenFunction::EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD,
// Don't insert type test assumes if we are forcing public
// visibility.
!CGM.AlwaysHasLTOVisibilityPublic(RD)) {
llvm::Metadata *MD =
CGM.CreateMetadataIdentifierForType(QualType(RD->getTypeForDecl(), 0));
QualType Ty = QualType(RD->getTypeForDecl(), 0);
llvm::Metadata *MD = CGM.CreateMetadataIdentifierForType(Ty);
llvm::Value *TypeId =
llvm::MetadataAsValue::get(CGM.getLLVMContext(), MD);
llvm::Value *CastedVTable = Builder.CreateBitCast(VTable, Int8PtrTy);
// If we already know that the call has hidden LTO visibility, emit
// @llvm.type.test(). Otherwise emit @llvm.public.type.test(), which WPD
// will convert to @llvm.type.test() if we assert at link time that we have
// whole program visibility.
llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
? llvm::Intrinsic::type_test
: llvm::Intrinsic::public_type_test;
llvm::Value *TypeTest =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::type_test),
{CastedVTable, TypeId});
Builder.CreateCall(CGM.getIntrinsic(IID), {CastedVTable, TypeId});
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::assume), TypeTest);
}
}

View File

@ -491,9 +491,11 @@ StringRef CGDebugInfo::getCurrentDirname() {
if (!CWDName.empty())
return CWDName;
SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
return CWDName = internString(CWD);
llvm::ErrorOr<std::string> CWD =
CGM.getFileSystem()->getCurrentWorkingDirectory();
if (!CWD)
return StringRef();
return CWDName = internString(*CWD);
}
void CGDebugInfo::CreateCompileUnit() {

View File

@ -2837,11 +2837,13 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
// Enter the continuation block and emit a phi if required.
CGF.EmitBlock(continueBB);
if (msgRet.isScalar()) {
llvm::Value *v = msgRet.getScalarVal();
llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
phi->addIncoming(v, nonNilPathBB);
phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
msgRet = RValue::get(phi);
// If the return type is void, do nothing
if (llvm::Value *v = msgRet.getScalarVal()) {
llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2);
phi->addIncoming(v, nonNilPathBB);
phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB);
msgRet = RValue::get(phi);
}
} else if (msgRet.isAggregate()) {
// Aggregate zeroing is handled in nilCleanupBB when it's required.
} else /* isComplex() */ {

View File

@ -186,17 +186,16 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime {
/// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32
/// global_tid, int proc_bind) to generate code for 'proc_bind' clause.
virtual void emitProcBindClause(CodeGenFunction &CGF,
llvm::omp::ProcBindKind ProcBind,
SourceLocation Loc) override;
void emitProcBindClause(CodeGenFunction &CGF,
llvm::omp::ProcBindKind ProcBind,
SourceLocation Loc) override;
/// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32
/// global_tid, kmp_int32 num_threads) to generate code for 'num_threads'
/// clause.
/// \param NumThreads An integer value of threads.
virtual void emitNumThreadsClause(CodeGenFunction &CGF,
llvm::Value *NumThreads,
SourceLocation Loc) override;
void emitNumThreadsClause(CodeGenFunction &CGF, llvm::Value *NumThreads,
SourceLocation Loc) override;
/// This function ought to emit, in the general case, a call to
// the openmp runtime kmpc_push_num_teams. In NVPTX backend it is not needed
@ -300,12 +299,12 @@ class CGOpenMPRuntimeGPU : public CGOpenMPRuntime {
/// SimpleReduction Emit reduction operation only. Used for omp simd
/// directive on the host.
/// ReductionKind The kind of reduction to perform.
virtual void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ArrayRef<const Expr *> Privates,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
ReductionOptionsTy Options) override;
void emitReduction(CodeGenFunction &CGF, SourceLocation Loc,
ArrayRef<const Expr *> Privates,
ArrayRef<const Expr *> LHSExprs,
ArrayRef<const Expr *> RHSExprs,
ArrayRef<const Expr *> ReductionOps,
ReductionOptionsTy Options) override;
/// Returns specified OpenMP runtime function for the current OpenMP
/// implementation. Specialized for the NVPTX device.

View File

@ -146,6 +146,7 @@ namespace clang {
public:
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
@ -159,8 +160,8 @@ namespace clang {
AsmOutStream(std::move(OS)), Context(nullptr),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, InFile, HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)),
Gen(CreateLLVMCodeGen(Diags, InFile, std::move(FS), HeaderSearchOpts,
PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
@ -171,6 +172,7 @@ namespace clang {
// to use the clang diagnostic handler for IR input files. It avoids
// initializing the OS field.
BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PPOpts,
const CodeGenOptions &CodeGenOpts,
@ -183,8 +185,8 @@ namespace clang {
Context(nullptr),
LLVMIRGeneration("irgen", "LLVM IR Generation Time"),
LLVMIRGenerationRefCount(0),
Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts,
CodeGenOpts, C, CoverageInfo)),
Gen(CreateLLVMCodeGen(Diags, "", std::move(FS), HeaderSearchOpts,
PPOpts, CodeGenOpts, C, CoverageInfo)),
LinkModules(std::move(LinkModules)), CurLinkModule(Module) {
TimerIsEnabled = CodeGenOpts.TimePasses;
llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
@ -1052,10 +1054,10 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
CI.getPreprocessor());
std::unique_ptr<BackendConsumer> Result(new BackendConsumer(
BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(), CI.getTargetOpts(),
CI.getLangOpts(), std::string(InFile), std::move(LinkModules),
std::move(OS), *VMContext, CoverageInfo));
BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
CI.getTargetOpts(), CI.getLangOpts(), std::string(InFile),
std::move(LinkModules), std::move(OS), *VMContext, CoverageInfo));
BEConsumer = Result.get();
// Enable generating macro debug info only when debug info is not disabled and
@ -1185,9 +1187,10 @@ void CodeGenAction::ExecuteAction() {
// Set clang diagnostic handler. To do this we need to create a fake
// BackendConsumer.
BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(),
CI.getPreprocessorOpts(), CI.getCodeGenOpts(),
CI.getTargetOpts(), CI.getLangOpts(), TheModule.get(),
BackendConsumer Result(BA, CI.getDiagnostics(), &CI.getVirtualFileSystem(),
CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(),
CI.getCodeGenOpts(), CI.getTargetOpts(),
CI.getLangOpts(), TheModule.get(),
std::move(LinkModules), *VMContext, nullptr);
// PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be
// true here because the valued names are needed for reading textual IR.

View File

@ -96,16 +96,18 @@ static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
llvm_unreachable("invalid C++ ABI kind");
}
CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
CodeGenModule::CodeGenModule(ASTContext &C,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HSO,
const PreprocessorOptions &PPO,
const CodeGenOptions &CGO, llvm::Module &M,
DiagnosticsEngine &diags,
CoverageSourceInfo *CoverageInfo)
: Context(C), LangOpts(C.getLangOpts()), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), TheModule(M), Diags(diags),
Target(C.getTargetInfo()), ABI(createCXXABI(*this)),
VMContext(M.getContext()), Types(*this), VTables(*this),
SanitizerMD(new SanitizerMetadata(*this)) {
: Context(C), LangOpts(C.getLangOpts()), FS(std::move(FS)),
HeaderSearchOpts(HSO), PreprocessorOpts(PPO), CodeGenOpts(CGO),
TheModule(M), Diags(diags), Target(C.getTargetInfo()),
ABI(createCXXABI(*this)), VMContext(M.getContext()), Types(*this),
VTables(*this), SanitizerMD(new SanitizerMetadata(*this)) {
// Initialize the type cache.
llvm::LLVMContext &LLVMContext = M.getContext();
@ -795,18 +797,17 @@ void CodeGenModule::Release() {
Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 ||
Arch == llvm::Triple::aarch64_be) {
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
LangOpts.BranchTargetEnforcement);
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address",
LangOpts.hasSignReturnAddress());
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
LangOpts.isSignReturnAddressScopeAll());
getModule().addModuleFlag(llvm::Module::Min,
"sign-return-address-with-bkey",
!LangOpts.isSignReturnAddressWithAKey());
if (LangOpts.BranchTargetEnforcement)
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
1);
if (LangOpts.hasSignReturnAddress())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
if (LangOpts.isSignReturnAddressScopeAll())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-all",
1);
if (!LangOpts.isSignReturnAddressWithAKey())
getModule().addModuleFlag(llvm::Module::Min,
"sign-return-address-with-bkey", 1);
}
if (!CodeGenOpts.MemoryProfileOutput.empty()) {
@ -7000,4 +7001,6 @@ void CodeGenModule::moveLazyEmissionStates(CodeGenModule *NewBuilder) {
"Still have (unmerged) EmittedDeferredDecls deferred decls");
NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls);
NewBuilder->ABI->MangleCtx = std::move(ABI->MangleCtx);
}

View File

@ -47,6 +47,10 @@ class DataLayout;
class FunctionType;
class LLVMContext;
class IndexedInstrProfReader;
namespace vfs {
class FileSystem;
}
}
namespace clang {
@ -293,6 +297,7 @@ class CodeGenModule : public CodeGenTypeCache {
private:
ASTContext &Context;
const LangOptions &LangOpts;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions &CodeGenOpts;
@ -584,7 +589,8 @@ class CodeGenModule : public CodeGenTypeCache {
llvm::DenseMap<const llvm::Constant *, llvm::GlobalVariable *> RTTIProxyMap;
public:
CodeGenModule(ASTContext &C, const HeaderSearchOptions &headersearchopts,
CodeGenModule(ASTContext &C, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &headersearchopts,
const PreprocessorOptions &ppopts,
const CodeGenOptions &CodeGenOpts, llvm::Module &M,
DiagnosticsEngine &Diags,
@ -712,6 +718,9 @@ class CodeGenModule : public CodeGenTypeCache {
ASTContext &getContext() const { return Context; }
const LangOptions &getLangOpts() const { return LangOpts; }
const IntrusiveRefCntPtr<llvm::vfs::FileSystem> &getFileSystem() const {
return FS;
}
const HeaderSearchOptions &getHeaderSearchOpts()
const { return HeaderSearchOpts; }
const PreprocessorOptions &getPreprocessorOpts()

View File

@ -707,8 +707,12 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
if (ShouldEmitCFICheck || ShouldEmitWPDInfo) {
llvm::Value *VFPAddr =
Builder.CreateGEP(CGF.Int8Ty, VTable, VTableOffset);
llvm::Intrinsic::ID IID = CGM.HasHiddenLTOVisibility(RD)
? llvm::Intrinsic::type_test
: llvm::Intrinsic::public_type_test;
CheckResult = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::type_test),
CGM.getIntrinsic(IID),
{Builder.CreateBitCast(VFPAddr, CGF.Int8PtrTy), TypeId});
}

View File

@ -782,7 +782,7 @@ class MicrosoftCXXABI : public CGCXXABI {
LoadVTablePtr(CodeGenFunction &CGF, Address This,
const CXXRecordDecl *RD) override;
virtual bool
bool
isPermittedToBeHomogeneousAggregate(const CXXRecordDecl *RD) const override;
private:

View File

@ -23,6 +23,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <memory>
using namespace clang;
@ -32,6 +33,7 @@ namespace {
class CodeGeneratorImpl : public CodeGenerator {
DiagnosticsEngine &Diags;
ASTContext *Ctx;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; // Only used for debug info.
const HeaderSearchOptions &HeaderSearchOpts; // Only used for debug info.
const PreprocessorOptions &PreprocessorOpts; // Only used for debug info.
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
@ -74,11 +76,12 @@ namespace {
public:
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HSO,
const PreprocessorOptions &PPO, const CodeGenOptions &CGO,
llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo = nullptr)
: Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
: Diags(diags), Ctx(nullptr), FS(std::move(FS)), HeaderSearchOpts(HSO),
PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
CoverageInfo(CoverageInfo),
M(new llvm::Module(ExpandModuleName(ModuleName, CGO), C)) {
@ -158,7 +161,7 @@ namespace {
if (auto TVSDKVersion =
Ctx->getTargetInfo().getDarwinTargetVariantSDKVersion())
M->setDarwinTargetVariantSDKVersion(*TVSDKVersion);
Builder.reset(new CodeGen::CodeGenModule(Context, HeaderSearchOpts,
Builder.reset(new CodeGen::CodeGenModule(Context, FS, HeaderSearchOpts,
PreprocessorOpts, CodeGenOpts,
*M, Diags, CoverageInfo));
@ -356,11 +359,14 @@ llvm::Module *CodeGenerator::StartModule(llvm::StringRef ModuleName,
return static_cast<CodeGeneratorImpl*>(this)->StartModule(ModuleName, C);
}
CodeGenerator *clang::CreateLLVMCodeGen(
DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts, const CodeGenOptions &CGO,
llvm::LLVMContext &C, CoverageSourceInfo *CoverageInfo) {
return new CodeGeneratorImpl(Diags, ModuleName, HeaderSearchOpts,
PreprocessorOpts, CGO, C, CoverageInfo);
CodeGenerator *
clang::CreateLLVMCodeGen(DiagnosticsEngine &Diags, llvm::StringRef ModuleName,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
const HeaderSearchOptions &HeaderSearchOpts,
const PreprocessorOptions &PreprocessorOpts,
const CodeGenOptions &CGO, llvm::LLVMContext &C,
CoverageSourceInfo *CoverageInfo) {
return new CodeGeneratorImpl(Diags, ModuleName, std::move(FS),
HeaderSearchOpts, PreprocessorOpts, CGO, C,
CoverageInfo);
}

View File

@ -45,6 +45,7 @@ class PCHContainerGenerator : public ASTConsumer {
const std::string OutputFileName;
ASTContext *Ctx;
ModuleMap &MMap;
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS;
const HeaderSearchOptions &HeaderSearchOpts;
const PreprocessorOptions &PreprocessorOpts;
CodeGenOptions CodeGenOpts;
@ -144,6 +145,7 @@ class PCHContainerGenerator : public ASTConsumer {
: Diags(CI.getDiagnostics()), MainFileName(MainFileName),
OutputFileName(OutputFileName), Ctx(nullptr),
MMap(CI.getPreprocessor().getHeaderSearchInfo().getModuleMap()),
FS(&CI.getVirtualFileSystem()),
HeaderSearchOpts(CI.getHeaderSearchOpts()),
PreprocessorOpts(CI.getPreprocessorOpts()),
TargetOpts(CI.getTargetOpts()), LangOpts(CI.getLangOpts()),
@ -173,7 +175,7 @@ class PCHContainerGenerator : public ASTConsumer {
M.reset(new llvm::Module(MainFileName, *VMContext));
M->setDataLayout(Ctx->getTargetInfo().getDataLayoutString());
Builder.reset(new CodeGen::CodeGenModule(
*Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
*Ctx, FS, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));
// Prepare CGDebugInfo to emit debug info for a clang module.
auto *DI = Builder->getModuleDebugInfo();

View File

@ -20,7 +20,6 @@
namespace llvm {
class GlobalVariable;
class Instruction;
class MDNode;
} // namespace llvm
namespace clang {

View File

@ -548,6 +548,11 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (CPUArg)
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures,
Triple, CPUArgFPUID);
// TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
// longstanding behavior.
(void)Args.getLastArg(options::OPT_mtune_EQ);
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
unsigned FPUID = llvm::ARM::FK_INVALID;
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);

View File

@ -107,6 +107,10 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) {
void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &Features) {
// TODO Handle -mtune=. Suppress -Wunused-command-line-argument as a
// longstanding behavior.
(void)Args.getLastArg(options::OPT_mtune_EQ);
if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe)
Features.push_back("+spe");

View File

@ -5112,6 +5112,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-mabi=vec-default");
}
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ_quadword_atomics)) {
if (!Triple.isOSAIX() || Triple.isPPC32())
D.Diag(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << RawTriple.str();
CmdArgs.push_back("-mabi=quadword-atomics");
}
if (Arg *A = Args.getLastArg(options::OPT_mlong_double_128)) {
// Emit the unsupported option error until the Clang's library integration
// support for 128-bit long double is available for AIX.

View File

@ -489,12 +489,14 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Vptr;
if (IsX86_64 || IsMIPS64) {
if (IsAArch64 || IsX86_64 || IsMIPS64) {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Thread;
}
if (IsX86 || IsX86_64) {
Res |= SanitizerKind::Function;
}
if (IsAArch64 || IsX86 || IsX86_64) {
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
@ -502,8 +504,6 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const {
if (IsAArch64 || IsX86_64) {
Res |= SanitizerKind::KernelAddress;
Res |= SanitizerKind::KernelMemory;
}
if (IsX86_64) {
Res |= SanitizerKind::Memory;
}
return Res;

View File

@ -84,11 +84,11 @@ bool EditedSource::canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs) {
deconstructMacroArgLoc(OrigLoc, ExpLoc, ArgUse);
auto I = ExpansionToArgMap.find(ExpLoc);
if (I != ExpansionToArgMap.end() &&
find_if(I->second, [&](const MacroArgUse &U) {
llvm::any_of(I->second, [&](const MacroArgUse &U) {
return ArgUse.Identifier == U.Identifier &&
std::tie(ArgUse.ImmediateExpansionLoc, ArgUse.UseLoc) !=
std::tie(U.ImmediateExpansionLoc, U.UseLoc);
}) != I->second.end()) {
})) {
// Trying to write in a macro argument input that has already been
// written by a previous commit for another expansion of the same macro
// argument name. For example:

View File

@ -239,55 +239,6 @@ bool FormatTokenLexer::tryMergeCSharpStringLiteral() {
if (Tokens.size() < 2)
return false;
// Interpolated strings could contain { } with " characters inside.
// $"{x ?? "null"}"
// should not be split into $"{x ?? ", null, "}" but should treated as a
// single string-literal.
//
// We opt not to try and format expressions inside {} within a C#
// interpolated string. Formatting expressions within an interpolated string
// would require similar work as that done for JavaScript template strings
// in `handleTemplateStrings()`.
auto &CSharpInterpolatedString = *(Tokens.end() - 2);
if (CSharpInterpolatedString->getType() == TT_CSharpStringLiteral &&
(CSharpInterpolatedString->TokenText.startswith(R"($")") ||
CSharpInterpolatedString->TokenText.startswith(R"($@")"))) {
int UnmatchedOpeningBraceCount = 0;
auto TokenTextSize = CSharpInterpolatedString->TokenText.size();
for (size_t Index = 0; Index < TokenTextSize; ++Index) {
char C = CSharpInterpolatedString->TokenText[Index];
if (C == '{') {
// "{{" inside an interpolated string is an escaped '{' so skip it.
if (Index + 1 < TokenTextSize &&
CSharpInterpolatedString->TokenText[Index + 1] == '{') {
++Index;
continue;
}
++UnmatchedOpeningBraceCount;
} else if (C == '}') {
// "}}" inside an interpolated string is an escaped '}' so skip it.
if (Index + 1 < TokenTextSize &&
CSharpInterpolatedString->TokenText[Index + 1] == '}') {
++Index;
continue;
}
--UnmatchedOpeningBraceCount;
}
}
if (UnmatchedOpeningBraceCount > 0) {
auto &NextToken = *(Tokens.end() - 1);
CSharpInterpolatedString->TokenText =
StringRef(CSharpInterpolatedString->TokenText.begin(),
NextToken->TokenText.end() -
CSharpInterpolatedString->TokenText.begin());
CSharpInterpolatedString->ColumnWidth += NextToken->ColumnWidth;
Tokens.erase(Tokens.end() - 1);
return true;
}
}
// Look for @"aaaaaa" or $"aaaaaa".
auto &String = *(Tokens.end() - 1);
if (!String->is(tok::string_literal))
@ -571,45 +522,105 @@ void FormatTokenLexer::tryParseJSRegexLiteral() {
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset)));
}
void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
FormatToken *CSharpStringLiteral = Tokens.back();
if (CSharpStringLiteral->getType() != TT_CSharpStringLiteral)
return;
// Deal with multiline strings.
if (!(CSharpStringLiteral->TokenText.startswith(R"(@")") ||
CSharpStringLiteral->TokenText.startswith(R"($@")"))) {
return;
}
const char *StrBegin =
Lex->getBufferLocation() - CSharpStringLiteral->TokenText.size();
const char *Offset = StrBegin;
if (CSharpStringLiteral->TokenText.startswith(R"(@")"))
Offset += 2;
else // CSharpStringLiteral->TokenText.startswith(R"($@")")
Offset += 3;
static auto lexCSharpString(const char *Begin, const char *End, bool Verbatim,
bool Interpolated) {
auto Repeated = [&Begin, End]() {
return Begin + 1 < End && Begin[1] == Begin[0];
};
// Look for a terminating '"' in the current file buffer.
// Make no effort to format code within an interpolated or verbatim string.
for (; Offset != Lex->getBuffer().end(); ++Offset) {
if (Offset[0] == '"') {
// "" within a verbatim string is an escaped double quote: skip it.
if (Offset + 1 < Lex->getBuffer().end() && Offset[1] == '"')
++Offset;
else
//
// Interpolated strings could contain { } with " characters inside.
// $"{x ?? "null"}"
// should not be split into $"{x ?? ", null, "}" but should be treated as a
// single string-literal.
//
// We opt not to try and format expressions inside {} within a C#
// interpolated string. Formatting expressions within an interpolated string
// would require similar work as that done for JavaScript template strings
// in `handleTemplateStrings()`.
for (int UnmatchedOpeningBraceCount = 0; Begin < End; ++Begin) {
switch (*Begin) {
case '\\':
if (!Verbatim)
++Begin;
break;
case '{':
if (Interpolated) {
// {{ inside an interpolated string is escaped, so skip it.
if (Repeated())
++Begin;
else
++UnmatchedOpeningBraceCount;
}
break;
case '}':
if (Interpolated) {
// }} inside an interpolated string is escaped, so skip it.
if (Repeated())
++Begin;
else if (UnmatchedOpeningBraceCount > 0)
--UnmatchedOpeningBraceCount;
else
return End;
}
break;
case '"':
if (UnmatchedOpeningBraceCount > 0)
break;
// "" within a verbatim string is an escaped double quote: skip it.
if (Verbatim && Repeated()) {
++Begin;
break;
}
return Begin;
}
}
return End;
}
void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
FormatToken *CSharpStringLiteral = Tokens.back();
if (CSharpStringLiteral->isNot(TT_CSharpStringLiteral))
return;
auto &TokenText = CSharpStringLiteral->TokenText;
bool Verbatim = false;
bool Interpolated = false;
if (TokenText.startswith(R"($@")")) {
Verbatim = true;
Interpolated = true;
} else if (TokenText.startswith(R"(@")")) {
Verbatim = true;
} else if (TokenText.startswith(R"($")")) {
Interpolated = true;
}
// Deal with multiline strings.
if (!Verbatim && !Interpolated)
return;
const char *StrBegin = Lex->getBufferLocation() - TokenText.size();
const char *Offset = StrBegin;
if (Verbatim && Interpolated)
Offset += 3;
else
Offset += 2;
const auto End = Lex->getBuffer().end();
Offset = lexCSharpString(Offset, End, Verbatim, Interpolated);
// Make no attempt to format code properly if a verbatim string is
// unterminated.
if (Offset == Lex->getBuffer().end())
if (Offset >= End)
return;
StringRef LiteralText(StrBegin, Offset - StrBegin + 1);
CSharpStringLiteral->TokenText = LiteralText;
TokenText = LiteralText;
// Adjust width for potentially multiline string literals.
size_t FirstBreak = LiteralText.find('\n');
@ -628,10 +639,8 @@ void FormatTokenLexer::handleCSharpVerbatimAndInterpolatedStrings() {
StartColumn, Style.TabWidth, Encoding);
}
SourceLocation loc = Offset < Lex->getBuffer().end()
? Lex->getSourceLocation(Offset + 1)
: SourceMgr.getLocForEndOfFile(ID);
resetLexer(SourceMgr.getFileOffset(loc));
assert(Offset < End);
resetLexer(SourceMgr.getFileOffset(Lex->getSourceLocation(Offset + 1)));
}
void FormatTokenLexer::handleTemplateStrings() {

View File

@ -1926,6 +1926,12 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.EnableAIXExtendedAltivecABI = O.matches(OPT_mabi_EQ_vec_extabi);
}
if (Arg *A = Args.getLastArg(OPT_mabi_EQ_quadword_atomics)) {
if (!T.isOSAIX() || T.isPPC32())
Diags.Report(diag::err_drv_unsupported_opt_for_target)
<< A->getSpelling() << T.str();
}
bool NeedLocTracking = false;
if (!Opts.OptRecordFile.empty())

View File

@ -17,7 +17,8 @@
* explicitly disallows `stdatomic.h` in the C mode via an `#error`. Fallback
* to the clang resource header until that is fully supported.
*/
#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>) && !defined(_MSC_VER)
#if __STDC_HOSTED__ && \
__has_include_next(<stdatomic.h>) && !(defined(_MSC_VER) && !defined(__cplusplus))
# include_next <stdatomic.h>
#else

View File

@ -21,7 +21,6 @@
namespace llvm {
class Error;
class Module;
namespace orc {
class LLJIT;
class ThreadSafeContext;

View File

@ -6344,23 +6344,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
diag::err_expected_member_name_or_semi)
<< (D.getDeclSpec().isEmpty() ? SourceRange()
: D.getDeclSpec().getSourceRange());
} else if (getLangOpts().CPlusPlus) {
if (Tok.isOneOf(tok::period, tok::arrow))
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
else {
SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
if (Tok.isAtStartOfLine() && Loc.isValid())
Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
else
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
}
} else {
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
diag::err_expected_either)
<< tok::identifier << tok::l_paren;
if (Tok.getKind() == tok::TokenKind::kw_while) {
Diag(Tok, diag::err_while_loop_outside_of_a_function);
} else if (getLangOpts().CPlusPlus) {
if (Tok.isOneOf(tok::period, tok::arrow))
Diag(Tok, diag::err_invalid_operator_on_type) << Tok.is(tok::arrow);
else {
SourceLocation Loc = D.getCXXScopeSpec().getEndLoc();
if (Tok.isAtStartOfLine() && Loc.isValid())
Diag(PP.getLocForEndOfToken(Loc), diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
else
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus;
}
} else {
Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
diag::err_expected_either)
<< tok::identifier << tok::l_paren;
}
}
D.SetIdentifier(nullptr, Tok.getLocation());
D.setInvalidType(true);

File diff suppressed because it is too large Load Diff

View File

@ -350,6 +350,16 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler {
Token &FirstToken) override;
};
struct PragmaRISCVHandler : public PragmaHandler {
PragmaRISCVHandler(Sema &Actions)
: PragmaHandler("riscv"), Actions(Actions) {}
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
Token &FirstToken) override;
private:
Sema &Actions;
};
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
for (auto &T : Toks)
T.setFlag(clang::Token::IsReinjected);
@ -493,6 +503,11 @@ void Parser::initializePragmaHandlers() {
MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>();
PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
if (getTargetInfo().getTriple().isRISCV()) {
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
}
}
void Parser::resetPragmaHandlers() {
@ -617,6 +632,11 @@ void Parser::resetPragmaHandlers() {
PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get());
MaxTokensTotalPragmaHandler.reset();
if (getTargetInfo().getTriple().isRISCV()) {
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
RISCVPragmaHandler.reset();
}
}
/// Handle the annotation token produced for #pragma unused(...)
@ -3929,3 +3949,35 @@ void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP,
PP.overrideMaxTokens(MaxTokens, Loc);
}
// Handle '#pragma clang riscv intrinsic vector'.
void PragmaRISCVHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducer Introducer,
Token &FirstToken) {
Token Tok;
PP.Lex(Tok);
IdentifierInfo *II = Tok.getIdentifierInfo();
if (!II || !II->isStr("intrinsic")) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
<< PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'intrinsic'";
return;
}
PP.Lex(Tok);
II = Tok.getIdentifierInfo();
if (!II || !II->isStr("vector")) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument)
<< PP.getSpelling(Tok) << "riscv" << /*Expected=*/true << "'vector'";
return;
}
PP.Lex(Tok);
if (Tok.isNot(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
<< "clang riscv intrinsic";
return;
}
Actions.DeclareRISCVVBuiltins = true;
}

View File

@ -153,7 +153,7 @@ bool Parser::ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned DiagID,
return true;
}
bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
bool Parser::ExpectAndConsumeSemi(unsigned DiagID, StringRef TokenUsed) {
if (TryConsumeToken(tok::semi))
return false;
@ -172,7 +172,7 @@ bool Parser::ExpectAndConsumeSemi(unsigned DiagID) {
return false;
}
return ExpectAndConsume(tok::semi, DiagID);
return ExpectAndConsume(tok::semi, DiagID , TokenUsed);
}
void Parser::ConsumeExtraSemi(ExtraSemiKind Kind, DeclSpec::TST TST) {

View File

@ -91,7 +91,7 @@ void Scope::Init(Scope *parent, unsigned flags) {
UsingDirectives.clear();
Entity = nullptr;
ErrorTrap.reset();
NRVO.setPointerAndInt(nullptr, false);
NRVO = None;
}
bool Scope::containedInPrototypeScope() const {
@ -118,19 +118,71 @@ void Scope::AddFlags(unsigned FlagsToSet) {
Flags |= FlagsToSet;
}
void Scope::mergeNRVOIntoParent() {
if (VarDecl *Candidate = NRVO.getPointer()) {
if (isDeclScope(Candidate))
Candidate->setNRVOVariable(true);
// The algorithm for updating NRVO candidate is as follows:
// 1. All previous candidates become invalid because a new NRVO candidate is
// obtained. Therefore, we need to clear return slots for other
// variables defined before the current return statement in the current
// scope and in outer scopes.
// 2. Store the new candidate if its return slot is available. Otherwise,
// there is no NRVO candidate so far.
void Scope::updateNRVOCandidate(VarDecl *VD) {
auto UpdateReturnSlotsInScopeForVD = [VD](Scope *S) -> bool {
bool IsReturnSlotFound = S->ReturnSlots.contains(VD);
// We found a candidate variable that can be put into a return slot.
// Clear the set, because other variables cannot occupy a return
// slot in the same scope.
S->ReturnSlots.clear();
if (IsReturnSlotFound)
S->ReturnSlots.insert(VD);
return IsReturnSlotFound;
};
bool CanBePutInReturnSlot = false;
for (auto *S = this; S; S = S->getParent()) {
CanBePutInReturnSlot |= UpdateReturnSlotsInScopeForVD(S);
if (S->getEntity())
break;
}
if (getEntity())
// Consider the variable as NRVO candidate if the return slot is available
// for it in the current scope, or if it can be available in outer scopes.
NRVO = CanBePutInReturnSlot ? VD : nullptr;
}
void Scope::applyNRVO() {
// There is no NRVO candidate in the current scope.
if (!NRVO.hasValue())
return;
if (NRVO.getInt())
getParent()->setNoNRVO();
else if (NRVO.getPointer())
getParent()->addNRVOCandidate(NRVO.getPointer());
if (*NRVO && isDeclScope(*NRVO))
NRVO.getValue()->setNRVOVariable(true);
// It's necessary to propagate NRVO candidate to the parent scope for cases
// when the parent scope doesn't contain a return statement.
// For example:
// X foo(bool b) {
// X x;
// if (b)
// return x;
// exit(0);
// }
// Also, we need to propagate nullptr value that means NRVO is not
// allowed in this scope.
// For example:
// X foo(bool b) {
// X x;
// if (b)
// return x;
// else
// return X(); // NRVO is not allowed
// }
if (!getEntity())
getParent()->NRVO = *NRVO;
}
LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
@ -193,8 +245,10 @@ void Scope::dumpImpl(raw_ostream &OS) const {
if (const DeclContext *DC = getEntity())
OS << "Entity : (clang::DeclContext*)" << DC << '\n';
if (NRVO.getInt())
OS << "NRVO not allowed\n";
else if (NRVO.getPointer())
OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n';
if (!NRVO)
OS << "there is no NRVO candidate\n";
else if (*NRVO)
OS << "NRVO candidate : (clang::VarDecl*)" << *NRVO << '\n';
else
OS << "NRVO is not allowed\n";
}

View File

@ -37,6 +37,7 @@
#include "clang/Sema/Initialization.h"
#include "clang/Sema/MultiplexExternalSemaSource.h"
#include "clang/Sema/ObjCMethodList.h"
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaConsumer.h"
@ -137,9 +138,9 @@ class SemaPPCallbacks : public PPCallbacks {
void reset() { S = nullptr; }
virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) override {
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
SrcMgr::CharacteristicKind FileType,
FileID PrevFID) override {
if (!S)
return;
switch (Reason) {

View File

@ -2092,7 +2092,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) {
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
S->mergeNRVOIntoParent();
S->applyNRVO();
if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@ -18899,14 +18899,24 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
const llvm::APSInt &InitVal = ECD->getInitVal();
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative())
NumPositiveBits = std::max(NumPositiveBits,
(unsigned)InitVal.getActiveBits());
else
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
// If the enumerator is zero that should still be counted as a positive
// bit since we need a bit to store the value zero.
unsigned ActiveBits = InitVal.getActiveBits();
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
} else {
NumNegativeBits = std::max(NumNegativeBits,
(unsigned)InitVal.getMinSignedBits());
}
}
// If we have have an empty set of enumerators we still need one bit.
// From [dcl.enum]p8
// If the enumerator-list is empty, the values of the enumeration are as if
// the enumeration had a single enumerator with value 0
if (!NumPositiveBits && !NumNegativeBits)
NumPositiveBits = 1;
// Figure out the type that should be used for this enum.
QualType BestType;
unsigned BestWidth;

View File

@ -13824,7 +13824,8 @@ static void CheckIdentityFieldAssignment(Expr *LHSExpr, Expr *RHSExpr,
// C99 6.5.16.1
QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
SourceLocation Loc,
QualType CompoundType) {
QualType CompoundType,
BinaryOperatorKind Opc) {
assert(!LHSExpr->hasPlaceholderType(BuiltinType::PseudoObject));
// Verify that LHS is a modifiable lvalue, and emit error if not.
@ -13937,10 +13938,18 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
// expression or an unevaluated operand
ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
} else {
// C++2a [expr.ass]p6:
// C++20 [expr.ass]p6:
// [Compound-assignment] expressions are deprecated if E1 has
// volatile-qualified type
Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
// volatile-qualified type and op is not one of the bitwise
// operators |, &, ˆ.
switch (Opc) {
case BO_OrAssign:
case BO_AndAssign:
case BO_XorAssign:
break;
default:
Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType;
}
}
}
@ -14879,7 +14888,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
switch (Opc) {
case BO_Assign:
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType());
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType(), Opc);
if (getLangOpts().CPlusPlus &&
LHS.get()->getObjectKind() != OK_ObjCProperty) {
VK = LHS.get()->getValueKind();
@ -14976,32 +14985,37 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
Opc == BO_DivAssign);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_RemAssign:
CompResultTy = CheckRemainderOperands(LHS, RHS, OpLoc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_AddAssign:
ConvertHalfVec = true;
CompResultTy = CheckAdditionOperands(LHS, RHS, OpLoc, Opc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_SubAssign:
ConvertHalfVec = true;
CompResultTy = CheckSubtractionOperands(LHS, RHS, OpLoc, &CompLHSTy);
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_ShlAssign:
case BO_ShrAssign:
CompResultTy = CheckShiftOperands(LHS, RHS, OpLoc, Opc, true);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_AndAssign:
case BO_OrAssign: // fallthrough
@ -15011,7 +15025,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc);
CompLHSTy = CompResultTy;
if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid())
ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy);
ResultTy =
CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy, Opc);
break;
case BO_Comma:
ResultTy = CheckCommaOperands(*this, LHS, RHS, OpLoc);

View File

@ -29,6 +29,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
@ -928,6 +929,14 @@ bool Sema::LookupBuiltin(LookupResult &R) {
}
}
if (DeclareRISCVVBuiltins) {
if (!RVIntrinsicManager)
RVIntrinsicManager = CreateRISCVIntrinsicManager(*this);
if (RVIntrinsicManager->CreateIntrinsicIfFound(R, II, PP))
return true;
}
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
// In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any
@ -3838,6 +3847,12 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
//
// C++20 [basic.lookup.argdep] p4.3
// -- are exported, are attached to a named module M, do not appear
// in the translation unit containing the point of the lookup, and
// have the same innermost enclosing non-inline namespace scope as
// a declaration of an associated entity attached to M.
DeclContext::lookup_result R = NS->lookup(Name);
for (auto *D : R) {
auto *Underlying = D;
@ -3858,6 +3873,36 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc,
if (isVisible(D)) {
Visible = true;
break;
} else if (getLangOpts().CPlusPlusModules &&
D->isInExportDeclContext()) {
// C++20 [basic.lookup.argdep] p4.3 .. are exported ...
Module *FM = D->getOwningModule();
// exports are only valid in module purview and outside of any
// PMF (although a PMF should not even be present in a module
// with an import).
assert(FM && FM->isModulePurview() && !FM->isPrivateModule() &&
"bad export context");
// .. are attached to a named module M, do not appear in the
// translation unit containing the point of the lookup..
if (!isModuleUnitOfCurrentTU(FM) &&
llvm::any_of(AssociatedClasses, [&](auto *E) {
// ... and have the same innermost enclosing non-inline
// namespace scope as a declaration of an associated entity
// attached to M
if (!E->hasOwningModule() ||
E->getOwningModule()->getTopLevelModuleName() !=
FM->getTopLevelModuleName())
return false;
// TODO: maybe this could be cached when generating the
// associated namespaces / entities.
DeclContext *Ctx = E->getDeclContext();
while (!Ctx->isFileContext() || Ctx->isInlineNamespace())
Ctx = Ctx->getParent();
return Ctx == NS;
})) {
Visible = true;
break;
}
}
} else if (D->getFriendObjectKind()) {
auto *RD = cast<CXXRecordDecl>(D->getLexicalDeclContext());

View File

@ -63,8 +63,9 @@ static ExprResult CreateFunctionRefExpr(
// being used.
if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc))
return ExprError();
DeclRefExpr *DRE = new (S.Context)
DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo);
DeclRefExpr *DRE =
DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(),
Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl);
if (HadMultipleCandidates)
DRE->setHadMultipleCandidates(true);
@ -6400,6 +6401,27 @@ void Sema::AddOverloadCandidate(
return;
}
// Functions with internal linkage are only viable in the same module unit.
if (auto *MF = Function->getOwningModule()) {
if (getLangOpts().CPlusPlusModules && !MF->isModuleMapModule() &&
!isModuleUnitOfCurrentTU(MF)) {
/// FIXME: Currently, the semantics of linkage in clang is slightly
/// different from the semantics in C++ spec. In C++ spec, only names
/// have linkage. So that all entities of the same should share one
/// linkage. But in clang, different entities of the same could have
/// different linkage.
NamedDecl *ND = Function;
if (auto *SpecInfo = Function->getTemplateSpecializationInfo())
ND = SpecInfo->getTemplate();
if (ND->getFormalLinkage() == Linkage::InternalLinkage) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_module_mismatched;
return;
}
}
}
if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() &&
!Function->getAttr<TargetAttr>()->isDefaultVersion()) {
Candidate.Viable = false;

View File

@ -0,0 +1,395 @@
//==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==//
//
// 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 implements name lookup for RISC-V vector intrinsic.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/RISCVIntrinsicManager.h"
#include "clang/Sema/Sema.h"
#include "clang/Support/RISCVVIntrinsicUtils.h"
#include "llvm/ADT/SmallVector.h"
#include <string>
#include <vector>
using namespace llvm;
using namespace clang;
using namespace clang::RISCV;
namespace {
// Function definition of a RVV intrinsic.
struct RVVIntrinsicDef {
/// Full function name with suffix, e.g. vadd_vv_i32m1.
std::string Name;
/// Overloaded function name, e.g. vadd.
std::string OverloadName;
/// Mapping to which clang built-in function, e.g. __builtin_rvv_vadd.
std::string BuiltinName;
/// Function signature, first element is return type.
RVVTypes Signature;
};
struct RVVOverloadIntrinsicDef {
// Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
SmallVector<size_t, 8> Indexes;
};
} // namespace
static const PrototypeDescriptor RVVSignatureTable[] = {
#define DECL_SIGNATURE_TABLE
#include "clang/Basic/riscv_vector_builtin_sema.inc"
#undef DECL_SIGNATURE_TABLE
};
static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
#define DECL_INTRINSIC_RECORDS
#include "clang/Basic/riscv_vector_builtin_sema.inc"
#undef DECL_INTRINSIC_RECORDS
};
// Get subsequence of signature table.
static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index,
uint8_t Length) {
return makeArrayRef(&RVVSignatureTable[Index], Length);
}
static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
QualType QT;
switch (Type->getScalarType()) {
case ScalarTypeKind::Void:
QT = Context.VoidTy;
break;
case ScalarTypeKind::Size_t:
QT = Context.getSizeType();
break;
case ScalarTypeKind::Ptrdiff_t:
QT = Context.getPointerDiffType();
break;
case ScalarTypeKind::UnsignedLong:
QT = Context.UnsignedLongTy;
break;
case ScalarTypeKind::SignedLong:
QT = Context.LongTy;
break;
case ScalarTypeKind::Boolean:
QT = Context.BoolTy;
break;
case ScalarTypeKind::SignedInteger:
QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
break;
case ScalarTypeKind::UnsignedInteger:
QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
break;
case ScalarTypeKind::Float:
switch (Type->getElementBitwidth()) {
case 64:
QT = Context.DoubleTy;
break;
case 32:
QT = Context.FloatTy;
break;
case 16:
QT = Context.Float16Ty;
break;
default:
llvm_unreachable("Unsupported floating point width.");
}
break;
case Invalid:
llvm_unreachable("Unhandled type.");
}
if (Type->isVector())
QT = Context.getScalableVectorType(QT, Type->getScale().getValue());
if (Type->isConstant())
QT = Context.getConstType(QT);
// Transform the type to a pointer as the last step, if necessary.
if (Type->isPointer())
QT = Context.getPointerType(QT);
return QT;
}
namespace {
class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
private:
Sema &S;
ASTContext &Context;
// List of all RVV intrinsic.
std::vector<RVVIntrinsicDef> IntrinsicList;
// Mapping function name to index of IntrinsicList.
StringMap<size_t> Intrinsics;
// Mapping function name to RVVOverloadIntrinsicDef.
StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;
// Create IntrinsicList
void InitIntrinsicList();
// Create RVVIntrinsicDef.
void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
StringRef OverloadedSuffixStr, bool IsMask,
RVVTypes &Types);
// Create FunctionDecl for a vector intrinsic.
void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
Preprocessor &PP, unsigned Index,
bool IsOverload);
public:
RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) {
InitIntrinsicList();
}
// Create RISC-V vector intrinsic and insert into symbol table if found, and
// return true, otherwise return false.
bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
Preprocessor &PP) override;
};
} // namespace
void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
const TargetInfo &TI = Context.getTargetInfo();
bool HasVectorFloat32 = TI.hasFeature("zve32f");
bool HasVectorFloat64 = TI.hasFeature("zve64d");
bool HasZvfh = TI.hasFeature("experimental-zvfh");
bool HasRV64 = TI.hasFeature("64bit");
bool HasFullMultiply = TI.hasFeature("v");
// Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
// in RISCVVEmitter.cpp.
for (auto &Record : RVVIntrinsicRecords) {
// Create Intrinsics for each type and LMUL.
BasicType BaseType = BasicType::Unknown;
ArrayRef<PrototypeDescriptor> BasicProtoSeq =
ProtoSeq2ArrayRef(Record.PrototypeIndex, Record.PrototypeLength);
ArrayRef<PrototypeDescriptor> SuffixProto =
ProtoSeq2ArrayRef(Record.SuffixIndex, Record.SuffixLength);
ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize);
llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false,
/*HasMaskedOffOperand=*/false,
Record.HasVL, Record.NF);
llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true,
Record.HasMaskedOffOperand,
Record.HasVL, Record.NF);
for (unsigned int TypeRangeMaskShift = 0;
TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
++TypeRangeMaskShift) {
unsigned int BaseTypeI = 1 << TypeRangeMaskShift;
BaseType = static_cast<BasicType>(BaseTypeI);
if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI)
continue;
// Check requirement.
if (BaseType == BasicType::Float16 && !HasZvfh)
continue;
if (BaseType == BasicType::Float32 && !HasVectorFloat32)
continue;
if (BaseType == BasicType::Float64 && !HasVectorFloat64)
continue;
if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) &&
!HasRV64)
continue;
if ((BaseType == BasicType::Int64) &&
((Record.RequiredExtensions & RVV_REQ_FullMultiply) ==
RVV_REQ_FullMultiply) &&
!HasFullMultiply)
continue;
// Expanded with different LMUL.
for (int Log2LMUL = -3; Log2LMUL <= 3; Log2LMUL++) {
if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
continue;
Optional<RVVTypes> Types =
RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
// Ignored to create new intrinsic if there are any illegal types.
if (!Types.hasValue())
continue;
std::string SuffixStr =
RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto);
std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
BaseType, Log2LMUL, OverloadedSuffixProto);
// Create non-masked intrinsic.
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types);
if (Record.HasMasked) {
// Create masked intrinsic.
Optional<RVVTypes> MaskTypes = RVVType::computeTypes(
BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
*MaskTypes);
}
}
}
}
}
// Compute name and signatures for intrinsic with practical types.
void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
const RVVIntrinsicRecord &Record, StringRef SuffixStr,
StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) {
// Function name, e.g. vadd_vv_i32m1.
std::string Name = Record.Name;
if (!SuffixStr.empty())
Name += "_" + SuffixStr.str();
if (IsMask)
Name += "_m";
// Overloaded function name, e.g. vadd.
std::string OverloadedName;
if (!Record.OverloadedName)
OverloadedName = StringRef(Record.Name).split("_").first.str();
else
OverloadedName = Record.OverloadedName;
if (!OverloadedSuffixStr.empty())
OverloadedName += "_" + OverloadedSuffixStr.str();
// clang built-in function name, e.g. __builtin_rvv_vadd.
std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
if (IsMask)
BuiltinName += "_m";
// Put into IntrinsicList.
size_t Index = IntrinsicList.size();
IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature});
// Creating mapping to Intrinsics.
Intrinsics.insert({Name, Index});
// Get the RVVOverloadIntrinsicDef.
RVVOverloadIntrinsicDef &OverloadIntrinsicDef =
OverloadIntrinsics[OverloadedName];
// And added the index.
OverloadIntrinsicDef.Indexes.push_back(Index);
}
void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR,
IdentifierInfo *II,
Preprocessor &PP,
unsigned Index,
bool IsOverload) {
ASTContext &Context = S.Context;
RVVIntrinsicDef &IDef = IntrinsicList[Index];
RVVTypes Sigs = IDef.Signature;
size_t SigLength = Sigs.size();
RVVType *ReturnType = Sigs[0];
QualType RetType = RVVType2Qual(Context, ReturnType);
SmallVector<QualType, 8> ArgTypes;
QualType BuiltinFuncType;
// Skip return type, and convert RVVType to QualType for arguments.
for (size_t i = 1; i < SigLength; ++i)
ArgTypes.push_back(RVVType2Qual(Context, Sigs[i]));
FunctionProtoType::ExtProtoInfo PI(
Context.getDefaultCallingConvention(false, false, true));
PI.Variadic = false;
SourceLocation Loc = LR.getNameLoc();
BuiltinFuncType = Context.getFunctionType(RetType, ArgTypes, PI);
DeclContext *Parent = Context.getTranslationUnitDecl();
FunctionDecl *RVVIntrinsicDecl = FunctionDecl::Create(
Context, Parent, Loc, Loc, II, BuiltinFuncType, /*TInfo=*/nullptr,
SC_Extern, S.getCurFPFeatures().isFPConstrained(),
/*isInlineSpecified*/ false,
/*hasWrittenPrototype*/ true);
// Create Decl objects for each parameter, adding them to the
// FunctionDecl.
const auto *FP = cast<FunctionProtoType>(BuiltinFuncType);
SmallVector<ParmVarDecl *, 8> ParmList;
for (unsigned IParm = 0, E = FP->getNumParams(); IParm != E; ++IParm) {
ParmVarDecl *Parm =
ParmVarDecl::Create(Context, RVVIntrinsicDecl, Loc, Loc, nullptr,
FP->getParamType(IParm), nullptr, SC_None, nullptr);
Parm->setScopeInfo(0, IParm);
ParmList.push_back(Parm);
}
RVVIntrinsicDecl->setParams(ParmList);
// Add function attributes.
if (IsOverload)
RVVIntrinsicDecl->addAttr(OverloadableAttr::CreateImplicit(Context));
// Setup alias to __builtin_rvv_*
IdentifierInfo &IntrinsicII = PP.getIdentifierTable().get(IDef.BuiltinName);
RVVIntrinsicDecl->addAttr(
BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII));
// Add to symbol table.
LR.addDecl(RVVIntrinsicDecl);
}
bool RISCVIntrinsicManagerImpl::CreateIntrinsicIfFound(LookupResult &LR,
IdentifierInfo *II,
Preprocessor &PP) {
StringRef Name = II->getName();
// Lookup the function name from the overload intrinsics first.
auto OvIItr = OverloadIntrinsics.find(Name);
if (OvIItr != OverloadIntrinsics.end()) {
const RVVOverloadIntrinsicDef &OvIntrinsicDef = OvIItr->second;
for (auto Index : OvIntrinsicDef.Indexes)
CreateRVVIntrinsicDecl(LR, II, PP, Index,
/*IsOverload*/ true);
// If we added overloads, need to resolve the lookup result.
LR.resolveKind();
return true;
}
// Lookup the function name from the intrinsics.
auto Itr = Intrinsics.find(Name);
if (Itr != Intrinsics.end()) {
CreateRVVIntrinsicDecl(LR, II, PP, Itr->second,
/*IsOverload*/ false);
return true;
}
// It's not an RVV intrinsics.
return false;
}
namespace clang {
std::unique_ptr<clang::sema::RISCVIntrinsicManager>
CreateRISCVIntrinsicManager(Sema &S) {
return std::make_unique<RISCVIntrinsicManagerImpl>(S);
}
} // namespace clang

View File

@ -3898,12 +3898,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
return R;
if (VarDecl *VD =
const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
CurScope->addNRVOCandidate(VD);
} else {
CurScope->setNoNRVO();
}
VarDecl *VD =
const_cast<VarDecl *>(cast<ReturnStmt>(R.get())->getNRVOCandidate());
CurScope->updateNRVOCandidate(VD);
CheckJumpOutOfSEHFinally(*this, ReturnLoc, *CurScope->getFnParent());

View File

@ -20,6 +20,7 @@
#include "clang/AST/TemplateName.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/Stack.h"
@ -8707,23 +8708,59 @@ Decl *Sema::ActOnConceptDefinition(Scope *S,
// Check for conflicting previous declaration.
DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc);
LookupResult Previous(*this, NameInfo, LookupOrdinaryName,
ForVisibleRedeclaration);
forRedeclarationInCurContext());
LookupName(Previous, S);
FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false,
/*AllowInlineNamespace*/false);
if (!Previous.empty()) {
auto *Old = Previous.getRepresentativeDecl();
Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition :
diag::err_redefinition_different_kind) << NewDecl->getDeclName();
Diag(Old->getLocation(), diag::note_previous_definition);
}
bool AddToScope = true;
CheckConceptRedefinition(NewDecl, Previous, AddToScope);
ActOnDocumentableDecl(NewDecl);
PushOnScopeChains(NewDecl, S);
if (AddToScope)
PushOnScopeChains(NewDecl, S);
return NewDecl;
}
void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl,
LookupResult &Previous, bool &AddToScope) {
AddToScope = true;
if (Previous.empty())
return;
auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl());
if (!OldConcept) {
auto *Old = Previous.getRepresentativeDecl();
Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind)
<< NewDecl->getDeclName();
notePreviousDefinition(Old, NewDecl->getLocation());
AddToScope = false;
return;
}
// Check if we can merge with a concept declaration.
bool IsSame = Context.isSameEntity(NewDecl, OldConcept);
if (!IsSame) {
Diag(NewDecl->getLocation(), diag::err_redefinition_different_concept)
<< NewDecl->getDeclName();
notePreviousDefinition(OldConcept, NewDecl->getLocation());
AddToScope = false;
return;
}
if (hasReachableDefinition(OldConcept)) {
Diag(NewDecl->getLocation(), diag::err_redefinition)
<< NewDecl->getDeclName();
notePreviousDefinition(OldConcept, NewDecl->getLocation());
AddToScope = false;
return;
}
if (!Previous.isSingleResult()) {
// FIXME: we should produce an error in case of ambig and failed lookups.
// Other decls (e.g. namespaces) also have this shortcoming.
return;
}
Context.setPrimaryMergedDecl(NewDecl, OldConcept);
}
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {

View File

@ -2926,7 +2926,8 @@ Attr *ASTRecordReader::readAttr() {
/// Reads attributes from the current stream position.
void ASTRecordReader::readAttributes(AttrVec &Attrs) {
for (unsigned I = 0, E = readInt(); I != E; ++I)
Attrs.push_back(readAttr());
if (auto *A = readAttr())
Attrs.push_back(A);
}
//===----------------------------------------------------------------------===//

View File

@ -4347,8 +4347,12 @@ void ASTWriter::WriteModuleFileExtension(Sema &SemaRef,
void ASTRecordWriter::AddAttr(const Attr *A) {
auto &Record = *this;
if (!A)
// FIXME: Clang can't handle the serialization/deserialization of
// preferred_name properly now. See
// https://github.com/llvm/llvm-project/issues/56490 for example.
if (!A || (isa<PreferredNameAttr>(A) && Writer->isWritingNamedModules()))
return Record.push_back(0);
Record.push_back(A->getKind() + 1); // FIXME: stable encoding, target attrs
Record.AddIdentifierRef(A->getAttrName());

View File

@ -26,9 +26,11 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
using namespace clang;
using namespace ento;
using namespace std::placeholders;
namespace {
struct AnyArgExpr {
@ -118,10 +120,14 @@ class CStringChecker : public Checker< eval::Call,
const LocationContext *LCtx,
const CallEvent *Call) const;
typedef void (CStringChecker::*FnCheck)(CheckerContext &,
const CallExpr *) const;
using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
const CallExpr *)>;
CallDescriptionMap<FnCheck> Callbacks = {
{{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy},
{{CDF_MaybeBuiltin, "memcpy", 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
{{CDF_MaybeBuiltin, "wmemcpy", 3},
std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
{{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
{{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
{{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
@ -135,7 +141,9 @@ class CStringChecker : public Checker< eval::Call,
{{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
{{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
{{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
{{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
{{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
{{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
{{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
@ -152,14 +160,14 @@ class CStringChecker : public Checker< eval::Call,
StdCopyBackward{{"std", "copy_backward"}, 3};
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
void evalMemcpy(CheckerContext &C, const CallExpr *CE) const;
void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest, SourceArgExpr Source,
bool Restricted, bool IsMempcpy) const;
bool Restricted, bool IsMempcpy, bool IsWide) const;
void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
@ -240,13 +248,14 @@ class CStringChecker : public Checker< eval::Call,
AnyArgExpr Arg, SVal l) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access) const;
AccessKind Access, bool IsWide = false) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
AccessKind Access) const;
AccessKind Access,
bool IsWide = false) const;
ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
AnyArgExpr Second) const;
AnyArgExpr Second, bool IsWide = false) const;
void emitOverlapBug(CheckerContext &C,
ProgramStateRef state,
const Stmt *First,
@ -329,7 +338,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access) const {
AccessKind Access,
bool IsWide) const {
// If a previous check has failed, propagate the failure.
if (!state)
@ -344,17 +354,36 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
if (!ER)
return state;
if (ER->getValueType() != C.getASTContext().CharTy)
return state;
SValBuilder &svalBuilder = C.getSValBuilder();
ASTContext &Ctx = svalBuilder.getContext();
// Get the index of the accessed element.
NonLoc Idx = ER->getIndex();
if (!IsWide) {
if (ER->getValueType() != Ctx.CharTy)
return state;
} else {
if (ER->getValueType() != Ctx.WideCharTy)
return state;
QualType SizeTy = Ctx.getSizeType();
NonLoc WideSize =
svalBuilder
.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
SizeTy)
.castAs<NonLoc>();
SVal Offset = svalBuilder.evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
if (Offset.isUnknown())
return state;
Idx = Offset.castAs<NonLoc>();
}
// Get the size of the array.
const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
DefinedOrUnknownSVal Size =
getDynamicExtent(state, superReg, C.getSValBuilder());
// Get the index of the accessed element.
DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
ProgramStateRef StInBound, StOutBound;
std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
if (StOutBound && !StInBound) {
@ -385,11 +414,10 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
return StInBound;
}
ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
ProgramStateRef State,
AnyArgExpr Buffer,
SizeArgExpr Size,
AccessKind Access) const {
ProgramStateRef
CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
AccessKind Access, bool IsWide) const {
// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;
@ -398,7 +426,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
ASTContext &Ctx = svalBuilder.getContext();
QualType SizeTy = Size.Expression->getType();
QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
// Check that the first buffer is non-null.
SVal BufVal = C.getSVal(Buffer.Expression);
@ -432,7 +460,7 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
State = CheckLocation(C, State, Buffer, BufEnd, Access);
State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
// If the buffer isn't large enough, abort.
if (!State)
@ -446,7 +474,8 @@ ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C,
ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
AnyArgExpr Second) const {
AnyArgExpr Second,
bool IsWide) const {
if (!Filter.CheckCStringBufferOverlap)
return state;
@ -525,7 +554,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Convert the first buffer's start address to char*.
// Bail out if the cast fails.
ASTContext &Ctx = svalBuilder.getContext();
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
SVal FirstStart =
svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
@ -1161,7 +1190,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest,
SourceArgExpr Source, bool Restricted,
bool IsMempcpy) const {
bool IsMempcpy, bool IsWide) const {
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
@ -1204,11 +1233,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
return;
// Ensure the accesses are valid and that the buffers do not overlap.
state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write);
state = CheckBufferAccess(C, state, Source, Size, AccessKind::read);
state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
if (Restricted)
state = CheckOverlap(C, state, Size, Dest, Source);
state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
if (!state)
return;
@ -1258,7 +1287,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
}
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
bool IsWide) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@ -1269,7 +1299,8 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy);
evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
IsWide);
}
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
@ -1281,7 +1312,8 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = true;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
false);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
@ -1293,7 +1325,8 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
false);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
@ -1304,7 +1337,8 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
false);
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
@ -2336,7 +2370,7 @@ bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
// Check and evaluate the call.
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
(this->*Callback)(C, CE);
Callback(this, C, CE);
// If the evaluate call resulted in no change, chain to the next eval call
// handler.

View File

@ -55,9 +55,9 @@ class InnerPointerChecker
ID.AddPointer(getTag());
}
virtual PathDiagnosticPieceRef
VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
PathSensitiveBugReport &BR) override;
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
BugReporterContext &BRC,
PathSensitiveBugReport &BR) override;
// FIXME: Scan the map once in the visitor's constructor and do a direct
// lookup by region.

View File

@ -852,9 +852,8 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
return false;
}
virtual bool
wasModifiedInFunction(const ExplodedNode *CallEnterN,
const ExplodedNode *CallExitEndN) override {
bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
const ExplodedNode *CallExitEndN) override {
if (!doesFnIntendToHandleOwnership(
CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
CallExitEndN->getState()->getAnalysisManager().getASTContext()))
@ -885,7 +884,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
"later deallocation");
}
virtual PathDiagnosticPieceRef
PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
const ObjCMethodCall &Call,
const ExplodedNode *N) override {
@ -893,7 +892,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
return nullptr;
}
virtual PathDiagnosticPieceRef
PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
const CXXConstructorCall &Call,
const ExplodedNode *N) override {
@ -901,7 +900,7 @@ class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
return nullptr;
}
virtual PathDiagnosticPieceRef
PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
const ExplodedNode *N) override {
// TODO: Factor the logic of "what constitutes as an entity being passed

View File

@ -182,7 +182,7 @@ class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
return false;
};
if (std::any_of(RD->field_begin(), RD->field_end(), IsTrickyField))
if (llvm::any_of(RD->fields(), IsTrickyField))
return true;
return false;
}

View File

@ -240,7 +240,7 @@ class StdLibraryFunctionsChecker
ArgNo OtherArgN;
public:
virtual StringRef getName() const override { return "Comparison"; };
StringRef getName() const override { return "Comparison"; };
ComparisonConstraint(ArgNo ArgN, BinaryOperator::Opcode Opcode,
ArgNo OtherArgN)
: ValueConstraint(ArgN), Opcode(Opcode), OtherArgN(OtherArgN) {}

View File

@ -57,19 +57,17 @@ class RegularField final : public FieldNode {
public:
RegularField(const FieldRegion *FR) : FieldNode(FR) {}
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "uninitialized field ";
}
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
void printPrefix(llvm::raw_ostream &Out) const override {}
virtual void printNode(llvm::raw_ostream &Out) const override {
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
virtual void printSeparator(llvm::raw_ostream &Out) const override {
Out << '.';
}
void printSeparator(llvm::raw_ostream &Out) const override { Out << '.'; }
};
/// Represents that the FieldNode that comes after this is declared in a base
@ -85,20 +83,20 @@ class BaseClass final : public FieldNode {
assert(T->getAsCXXRecordDecl());
}
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
void printNoteMsg(llvm::raw_ostream &Out) const override {
llvm_unreachable("This node can never be the final node in the "
"fieldchain!");
}
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
void printPrefix(llvm::raw_ostream &Out) const override {}
virtual void printNode(llvm::raw_ostream &Out) const override {
void printNode(llvm::raw_ostream &Out) const override {
Out << BaseClassT->getAsCXXRecordDecl()->getName() << "::";
}
virtual void printSeparator(llvm::raw_ostream &Out) const override {}
void printSeparator(llvm::raw_ostream &Out) const override {}
virtual bool isBase() const override { return true; }
bool isBase() const override { return true; }
};
} // end of anonymous namespace

View File

@ -34,20 +34,20 @@ class LocField final : public FieldNode {
LocField(const FieldRegion *FR, const bool IsDereferenced = true)
: FieldNode(FR), IsDereferenced(IsDereferenced) {}
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
void printNoteMsg(llvm::raw_ostream &Out) const override {
if (IsDereferenced)
Out << "uninitialized pointee ";
else
Out << "uninitialized pointer ";
}
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
void printPrefix(llvm::raw_ostream &Out) const override {}
virtual void printNode(llvm::raw_ostream &Out) const override {
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
virtual void printSeparator(llvm::raw_ostream &Out) const override {
void printSeparator(llvm::raw_ostream &Out) const override {
if (getDecl()->getType()->isPointerType())
Out << "->";
else
@ -64,11 +64,11 @@ class NeedsCastLocField final : public FieldNode {
NeedsCastLocField(const FieldRegion *FR, const QualType &T)
: FieldNode(FR), CastBackType(T) {}
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "uninitialized pointee ";
}
virtual void printPrefix(llvm::raw_ostream &Out) const override {
void printPrefix(llvm::raw_ostream &Out) const override {
// If this object is a nonloc::LocAsInteger.
if (getDecl()->getType()->isIntegerType())
Out << "reinterpret_cast";
@ -78,13 +78,11 @@ class NeedsCastLocField final : public FieldNode {
Out << '<' << CastBackType.getAsString() << ">(";
}
virtual void printNode(llvm::raw_ostream &Out) const override {
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl()) << ')';
}
virtual void printSeparator(llvm::raw_ostream &Out) const override {
Out << "->";
}
void printSeparator(llvm::raw_ostream &Out) const override { Out << "->"; }
};
/// Represents a Loc field that points to itself.
@ -93,17 +91,17 @@ class CyclicLocField final : public FieldNode {
public:
CyclicLocField(const FieldRegion *FR) : FieldNode(FR) {}
virtual void printNoteMsg(llvm::raw_ostream &Out) const override {
void printNoteMsg(llvm::raw_ostream &Out) const override {
Out << "object references itself ";
}
virtual void printPrefix(llvm::raw_ostream &Out) const override {}
void printPrefix(llvm::raw_ostream &Out) const override {}
virtual void printNode(llvm::raw_ostream &Out) const override {
void printNode(llvm::raw_ostream &Out) const override {
Out << getVariableName(getDecl());
}
virtual void printSeparator(llvm::raw_ostream &Out) const override {
void printSeparator(llvm::raw_ostream &Out) const override {
llvm_unreachable("CyclicLocField objects must be the last node of the "
"fieldchain!");
}

View File

@ -530,9 +530,8 @@ class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
private:
/// \return Whether \c RegionOfInterest was modified at \p CurrN compared to
/// the value it holds in \p CallExitBeginN.
virtual bool
wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
const ExplodedNode *CallExitBeginN) override;
bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
const ExplodedNode *CallExitBeginN) override;
/// Attempts to find the region of interest in a given record decl,
/// by either following the base classes or fields.
@ -547,19 +546,17 @@ class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor {
// Region of interest corresponds to an IVar, exiting a method
// which could have written into that IVar, but did not.
virtual PathDiagnosticPieceRef
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
const ObjCMethodCall &Call,
const ExplodedNode *N) override final;
PathDiagnosticPieceRef maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
const ObjCMethodCall &Call,
const ExplodedNode *N) final;
virtual PathDiagnosticPieceRef
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
const CXXConstructorCall &Call,
const ExplodedNode *N) override final;
PathDiagnosticPieceRef maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
const CXXConstructorCall &Call,
const ExplodedNode *N) final;
virtual PathDiagnosticPieceRef
PathDiagnosticPieceRef
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
const ExplodedNode *N) override final;
const ExplodedNode *N) final;
/// Consume the information on the no-store stack frame in order to
/// either emit a note or suppress the report enirely.

View File

@ -196,6 +196,14 @@ typedef llvm::ImmutableMap<
IndexOfElementToConstructMap;
REGISTER_TRAIT_WITH_PROGRAMSTATE(IndexOfElementToConstruct,
IndexOfElementToConstructMap)
// This trait is responsible for holding our pending ArrayInitLoopExprs.
// It pairs the LocationContext and the initializer CXXConstructExpr with
// the size of the array that's being copy initialized.
typedef llvm::ImmutableMap<
std::pair<const CXXConstructExpr *, const LocationContext *>, unsigned>
PendingInitLoopMap;
REGISTER_TRAIT_WITH_PROGRAMSTATE(PendingInitLoop, PendingInitLoopMap)
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@ -462,6 +470,34 @@ ProgramStateRef ExprEngine::setIndexOfElementToConstruct(
return State->set<IndexOfElementToConstruct>(Key, Idx);
}
Optional<unsigned> ExprEngine::getPendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx) {
return Optional<unsigned>::create(
State->get<PendingInitLoop>({E, LCtx->getStackFrame()}));
}
ProgramStateRef ExprEngine::removePendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx) {
auto Key = std::make_pair(E, LCtx->getStackFrame());
assert(E && State->contains<PendingInitLoop>(Key));
return State->remove<PendingInitLoop>(Key);
}
ProgramStateRef ExprEngine::setPendingInitLoop(ProgramStateRef State,
const CXXConstructExpr *E,
const LocationContext *LCtx,
unsigned Size) {
auto Key = std::make_pair(E, LCtx->getStackFrame());
assert(!State->contains<PendingInitLoop>(Key) && Size > 0);
return State->set<PendingInitLoop>(Key, Size);
}
Optional<unsigned>
ExprEngine::getIndexOfElementToConstruct(ProgramStateRef State,
const CXXConstructExpr *E,
@ -487,17 +523,23 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
const LocationContext *LC, SVal V) {
ConstructedObjectKey Key(Item, LC->getStackFrame());
const CXXConstructExpr *E = nullptr;
const Expr *Init = nullptr;
if (auto DS = dyn_cast_or_null<DeclStmt>(Item.getStmtOrNull())) {
if (auto VD = dyn_cast_or_null<VarDecl>(DS->getSingleDecl()))
E = dyn_cast<CXXConstructExpr>(VD->getInit());
Init = VD->getInit();
}
if (!E && !Item.getStmtOrNull()) {
auto CtorInit = Item.getCXXCtorInitializer();
E = dyn_cast<CXXConstructExpr>(CtorInit->getInit());
}
if (auto LE = dyn_cast_or_null<LambdaExpr>(Item.getStmtOrNull()))
Init = *(LE->capture_init_begin() + Item.getIndex());
if (!Init && !Item.getStmtOrNull())
Init = Item.getCXXCtorInitializer()->getInit();
// In an ArrayInitLoopExpr the real initializer is returned by
// getSubExpr().
if (const auto *AILE = dyn_cast_or_null<ArrayInitLoopExpr>(Init))
Init = AILE->getSubExpr();
// FIXME: Currently the state might already contain the marker due to
// incorrect handling of temporaries bound to default parameters.
@ -508,7 +550,8 @@ ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
assert((!State->get<ObjectsUnderConstruction>(Key) ||
Key.getItem().getKind() ==
ConstructionContextItem::TemporaryDestructorKind ||
State->contains<IndexOfElementToConstruct>({E, LC})) &&
State->contains<IndexOfElementToConstruct>(
{dyn_cast_or_null<CXXConstructExpr>(Init), LC})) &&
"The object is already marked as `UnderConstruction`, when it's not "
"supposed to!");
return State->set<ObjectsUnderConstruction>(Key, V);
@ -2744,7 +2787,10 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
SVal Base = state->getLValue(DD, LCtx);
if (DD->getType()->isReferenceType()) {
Base = state->getSVal(Base.getAsRegion());
if (const MemRegion *R = Base.getAsRegion())
Base = state->getSVal(R);
else
Base = UnknownVal();
}
SVal V = UnknownVal();
@ -2765,15 +2811,27 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
V = state->getLValue(BD->getType(), Idx, Base);
}
// Handle binding to tuple-like strcutures
else if (BD->getHoldingVar()) {
// FIXME: handle tuples
return;
// Handle binding to tuple-like structures
else if (const auto *HV = BD->getHoldingVar()) {
V = state->getLValue(HV, LCtx);
if (HV->getType()->isReferenceType()) {
if (const MemRegion *R = V.getAsRegion())
V = state->getSVal(R);
else
V = UnknownVal();
}
} else
llvm_unreachable("An unknown case of structured binding encountered!");
if (BD->getType()->isReferenceType())
V = state->getSVal(V.getAsRegion());
// In case of tuple-like types the references are already handled, so we
// don't want to handle them again.
if (BD->getType()->isReferenceType() && !BD->getHoldingVar()) {
if (const MemRegion *R = V.getAsRegion())
V = state->getSVal(R);
else
V = UnknownVal();
}
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), nullptr,
ProgramPoint::PostLValueKind);
@ -2797,6 +2855,11 @@ void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex,
const Expr *Arr = Ex->getCommonExpr()->getSourceExpr();
for (auto *Node : CheckerPreStmt) {
// The constructor visitior has already taken care of everything.
if (auto *CE = dyn_cast<CXXConstructExpr>(Ex->getSubExpr()))
break;
const LocationContext *LCtx = Node->getLocationContext();
ProgramStateRef state = Node->getState();

Some files were not shown because too many files have changed in this diff Show More