136 changes: 93 additions & 43 deletions clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H

#include <type_traits>

#include "clang/AST/AST.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/DenseMap.h"
#include <memory>

namespace clang {

Expand All @@ -21,75 +19,127 @@ class FunctionParmMutationAnalyzer;
/// Analyzes whether any mutative operations are applied to an expression within
/// a given statement.
class ExprMutationAnalyzer {
friend class FunctionParmMutationAnalyzer;

public:
struct Memoized {
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
using FunctionParaAnalyzerMap =
llvm::SmallDenseMap<const FunctionDecl *,
std::unique_ptr<FunctionParmMutationAnalyzer>>;

ResultMap Results;
ResultMap PointeeResults;
FunctionParaAnalyzerMap FuncParmAnalyzer;

void clear() {
Results.clear();
PointeeResults.clear();
FuncParmAnalyzer.clear();
}
};
struct Analyzer {
Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized)
: Stm(Stm), Context(Context), Memorized(Memorized) {}

const Stmt *findMutation(const Expr *Exp);
const Stmt *findMutation(const Decl *Dec);

const Stmt *findPointeeMutation(const Expr *Exp);
const Stmt *findPointeeMutation(const Decl *Dec);
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context);

private:
using MutationFinder = const Stmt *(Analyzer::*)(const Expr *);

const Stmt *findMutationMemoized(const Expr *Exp,
llvm::ArrayRef<MutationFinder> Finders,
Memoized::ResultMap &MemoizedResults);
const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);

bool isUnevaluated(const Expr *Exp);

const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);

const Stmt *findDirectMutation(const Expr *Exp);
const Stmt *findMemberMutation(const Expr *Exp);
const Stmt *findArrayElementMutation(const Expr *Exp);
const Stmt *findCastMutation(const Expr *Exp);
const Stmt *findRangeLoopMutation(const Expr *Exp);
const Stmt *findReferenceMutation(const Expr *Exp);
const Stmt *findFunctionArgMutation(const Expr *Exp);

const Stmt &Stm;
ASTContext &Context;
Memoized &Memorized;
};

ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
: Stm(Stm), Context(Context) {}
: Memorized(), A(Stm, Context, Memorized) {}

bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
const Stmt *findMutation(const Expr *Exp);
const Stmt *findMutation(const Decl *Dec);
const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }

bool isPointeeMutated(const Expr *Exp) {
return findPointeeMutation(Exp) != nullptr;
}
bool isPointeeMutated(const Decl *Dec) {
return findPointeeMutation(Dec) != nullptr;
}
const Stmt *findPointeeMutation(const Expr *Exp);
const Stmt *findPointeeMutation(const Decl *Dec);
const Stmt *findPointeeMutation(const Expr *Exp) {
return A.findPointeeMutation(Exp);
}
const Stmt *findPointeeMutation(const Decl *Dec) {
return A.findPointeeMutation(Dec);
}

static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context);
ASTContext &Context) {
return Analyzer::isUnevaluated(Smt, Stm, Context);
}

private:
using MutationFinder = const Stmt *(ExprMutationAnalyzer::*)(const Expr *);
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;

const Stmt *findMutationMemoized(const Expr *Exp,
llvm::ArrayRef<MutationFinder> Finders,
ResultMap &MemoizedResults);
const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);

bool isUnevaluated(const Expr *Exp);

const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);

const Stmt *findDirectMutation(const Expr *Exp);
const Stmt *findMemberMutation(const Expr *Exp);
const Stmt *findArrayElementMutation(const Expr *Exp);
const Stmt *findCastMutation(const Expr *Exp);
const Stmt *findRangeLoopMutation(const Expr *Exp);
const Stmt *findReferenceMutation(const Expr *Exp);
const Stmt *findFunctionArgMutation(const Expr *Exp);

const Stmt &Stm;
ASTContext &Context;
llvm::DenseMap<const FunctionDecl *,
std::unique_ptr<FunctionParmMutationAnalyzer>>
FuncParmAnalyzer;
ResultMap Results;
ResultMap PointeeResults;
Memoized Memorized;
Analyzer A;
};

// A convenient wrapper around ExprMutationAnalyzer for analyzing function
// params.
class FunctionParmMutationAnalyzer {
public:
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context);
static FunctionParmMutationAnalyzer *
getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized) {
auto it = Memorized.FuncParmAnalyzer.find(&Func);
if (it == Memorized.FuncParmAnalyzer.end())
it =
Memorized.FuncParmAnalyzer
.try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>(
new FunctionParmMutationAnalyzer(
Func, Context, Memorized)))
.first;
return it->getSecond().get();
}

bool isMutated(const ParmVarDecl *Parm) {
return findMutation(Parm) != nullptr;
}
const Stmt *findMutation(const ParmVarDecl *Parm);

private:
ExprMutationAnalyzer BodyAnalyzer;
ExprMutationAnalyzer::Analyzer BodyAnalyzer;
llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;

FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized);
};

} // namespace clang
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,12 @@ def Unreachable : Builtin {
let Prototype = "void()";
}

def AllowRuntimeCheck : Builtin {
let Spellings = ["__builtin_allow_runtime_check"];
let Attributes = [NoThrow, Pure, Const];
let Prototype = "bool(char const*)";
}

def ShuffleVector : Builtin {
let Spellings = ["__builtin_shufflevector"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/arm_fp16.td
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
include "arm_neon_incl.td"

// ARMv8.2-A FP16 intrinsics.
let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fullfp16" in {

// Negate
def VNEGSH : SInst<"vneg", "11", "Sh">;
Expand Down
58 changes: 29 additions & 29 deletions clang/include/clang/Basic/arm_neon.td
Original file line number Diff line number Diff line change
Expand Up @@ -605,11 +605,11 @@ def VQDMULL_LANE : SOpInst<"vqdmull_lane", "(>Q)..I", "si", OP_QDMULL_LN>;
def VQDMULH_N : SOpInst<"vqdmulh_n", "..1", "siQsQi", OP_QDMULH_N>;
def VQRDMULH_N : SOpInst<"vqrdmulh_n", "..1", "siQsQi", OP_QRDMULH_N>;

let ArchGuard = "!defined(__aarch64__)" in {
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)" in {
def VQDMULH_LANE : SOpInst<"vqdmulh_lane", "..qI", "siQsQi", OP_QDMULH_LN>;
def VQRDMULH_LANE : SOpInst<"vqrdmulh_lane", "..qI", "siQsQi", OP_QRDMULH_LN>;
}
let ArchGuard = "defined(__aarch64__)" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {
def A64_VQDMULH_LANE : SInst<"vqdmulh_lane", "..(!q)I", "siQsQi">;
def A64_VQRDMULH_LANE : SInst<"vqrdmulh_lane", "..(!q)I", "siQsQi">;
}
Expand Down Expand Up @@ -686,7 +686,7 @@ multiclass REINTERPRET_CROSS_TYPES<string TypesA, string TypesB> {

// E.3.31 Vector reinterpret cast operations
def VREINTERPRET : REINTERPRET_CROSS_SELF<"csilUcUsUiUlhfPcPsQcQsQiQlQUcQUsQUiQUlQhQfQPcQPs"> {
let ArchGuard = "!defined(__aarch64__)";
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)";
let BigEndianSafe = 1;
}

Expand Down Expand Up @@ -714,7 +714,7 @@ def VADDP : WInst<"vadd", "...", "PcPsPlQPcQPsQPl">;
////////////////////////////////////////////////////////////////////////////////
// AArch64 Intrinsics

let ArchGuard = "defined(__aarch64__)" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {

////////////////////////////////////////////////////////////////////////////////
// Load/Store
Expand Down Expand Up @@ -1091,14 +1091,14 @@ let isLaneQ = 1 in {
def VQDMULH_LANEQ : SInst<"vqdmulh_laneq", "..QI", "siQsQi">;
def VQRDMULH_LANEQ : SInst<"vqrdmulh_laneq", "..QI", "siQsQi">;
}
let ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.1a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a" in {
def VQRDMLAH_LANEQ : SOpInst<"vqrdmlah_laneq", "...QI", "siQsQi", OP_QRDMLAH_LN> {
let isLaneQ = 1;
}
def VQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "...QI", "siQsQi", OP_QRDMLSH_LN> {
let isLaneQ = 1;
}
} // ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.1a"
} // ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a"

// Note: d type implemented by SCALAR_VMULX_LANE
def VMULX_LANE : IOpInst<"vmulx_lane", "..qI", "fQfQd", OP_MULX_LN>;
Expand Down Expand Up @@ -1143,7 +1143,7 @@ def SHA256H2 : SInst<"vsha256h2", "....", "QUi">;
def SHA256SU1 : SInst<"vsha256su1", "....", "QUi">;
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "sha3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3" in {
def BCAX : SInst<"vbcax", "....", "QUcQUsQUiQUlQcQsQiQl">;
def EOR3 : SInst<"veor3", "....", "QUcQUsQUiQUlQcQsQiQl">;
def RAX1 : SInst<"vrax1", "...", "QUl">;
Expand All @@ -1153,14 +1153,14 @@ def XAR : SInst<"vxar", "...I", "QUl">;
}
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "sha3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sha3" in {
def SHA512SU0 : SInst<"vsha512su0", "...", "QUl">;
def SHA512su1 : SInst<"vsha512su1", "....", "QUl">;
def SHA512H : SInst<"vsha512h", "....", "QUl">;
def SHA512H2 : SInst<"vsha512h2", "....", "QUl">;
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "sm4" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4" in {
def SM3SS1 : SInst<"vsm3ss1", "....", "QUi">;
def SM3TT1A : SInst<"vsm3tt1a", "....I", "QUi">;
def SM3TT1B : SInst<"vsm3tt1b", "....I", "QUi">;
Expand All @@ -1170,7 +1170,7 @@ def SM3PARTW1 : SInst<"vsm3partw1", "....", "QUi">;
def SM3PARTW2 : SInst<"vsm3partw2", "....", "QUi">;
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "sm4" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "sm4" in {
def SM4E : SInst<"vsm4e", "...", "QUi">;
def SM4EKEY : SInst<"vsm4ekey", "...", "QUi">;
}
Expand All @@ -1193,7 +1193,7 @@ def FCVTAS_S32 : SInst<"vcvta_s32", "S.", "fQf">;
def FCVTAU_S32 : SInst<"vcvta_u32", "U.", "fQf">;
}

let ArchGuard = "defined(__aarch64__)" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {
def FCVTNS_S64 : SInst<"vcvtn_s64", "S.", "dQd">;
def FCVTNU_S64 : SInst<"vcvtn_u64", "U.", "dQd">;
def FCVTPS_S64 : SInst<"vcvtp_s64", "S.", "dQd">;
Expand All @@ -1217,7 +1217,7 @@ def FRINTZ_S32 : SInst<"vrnd", "..", "fQf">;
def FRINTI_S32 : SInst<"vrndi", "..", "fQf">;
}

let ArchGuard = "defined(__aarch64__) && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in {
let ArchGuard = "(defined(__aarch64__) || defined(__arm64ec__)) && defined(__ARM_FEATURE_DIRECTED_ROUNDING)" in {
def FRINTN_S64 : SInst<"vrndn", "..", "dQd">;
def FRINTA_S64 : SInst<"vrnda", "..", "dQd">;
def FRINTP_S64 : SInst<"vrndp", "..", "dQd">;
Expand All @@ -1227,7 +1227,7 @@ def FRINTZ_S64 : SInst<"vrnd", "..", "dQd">;
def FRINTI_S64 : SInst<"vrndi", "..", "dQd">;
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.5a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.5a" in {
def FRINT32X_S32 : SInst<"vrnd32x", "..", "fQf">;
def FRINT32Z_S32 : SInst<"vrnd32z", "..", "fQf">;
def FRINT64X_S32 : SInst<"vrnd64x", "..", "fQf">;
Expand All @@ -1247,7 +1247,7 @@ def FMAXNM_S32 : SInst<"vmaxnm", "...", "fQf">;
def FMINNM_S32 : SInst<"vminnm", "...", "fQf">;
}

let ArchGuard = "defined(__aarch64__) && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in {
let ArchGuard = "(defined(__aarch64__) || defined(__arm64ec__)) && defined(__ARM_FEATURE_NUMERIC_MAXMIN)" in {
def FMAXNM_S64 : SInst<"vmaxnm", "...", "dQd">;
def FMINNM_S64 : SInst<"vminnm", "...", "dQd">;
}
Expand Down Expand Up @@ -1289,7 +1289,7 @@ def VQTBX4_A64 : WInst<"vqtbx4", "..(4Q)U", "UccPcQUcQcQPc">;
// itself during generation so, unlike all other intrinsics, this one should
// include *all* types, not just additional ones.
def VVREINTERPRET : REINTERPRET_CROSS_SELF<"csilUcUsUiUlhfdPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQdQPcQPsQPlQPk"> {
let ArchGuard = "defined(__aarch64__)";
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)";
let BigEndianSafe = 1;
}

Expand Down Expand Up @@ -1401,15 +1401,15 @@ def SCALAR_SQDMULH : SInst<"vqdmulh", "111", "SsSi">;
// Scalar Integer Saturating Rounding Doubling Multiply Half High
def SCALAR_SQRDMULH : SInst<"vqrdmulh", "111", "SsSi">;

let ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.1a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a" in {
////////////////////////////////////////////////////////////////////////////////
// Signed Saturating Rounding Doubling Multiply Accumulate Returning High Half
def SCALAR_SQRDMLAH : SInst<"vqrdmlah", "1111", "SsSi">;

////////////////////////////////////////////////////////////////////////////////
// Signed Saturating Rounding Doubling Multiply Subtract Returning High Half
def SCALAR_SQRDMLSH : SInst<"vqrdmlsh", "1111", "SsSi">;
} // ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.1a"
} // ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.1a"

////////////////////////////////////////////////////////////////////////////////
// Scalar Floating-point Multiply Extended
Expand Down Expand Up @@ -1651,7 +1651,7 @@ def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "1QI", "ScSsSiSlSfSdSUcSUsSUiSUlSPcS
let isLaneQ = 1;
}

} // ArchGuard = "defined(__aarch64__)"
} // ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)"

// ARMv8.2-A FP16 vector intrinsics for A32/A64.
let TargetGuard = "fullfp16" in {
Expand Down Expand Up @@ -1775,7 +1775,7 @@ def VEXTH : WInst<"vext", "...I", "hQh">;
def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>;

// ARMv8.2-A FP16 vector intrinsics for A64 only.
let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fullfp16" in {

// Vector rounding
def FRINTIH : SInst<"vrndi", "..", "hQh">;
Expand Down Expand Up @@ -1856,7 +1856,7 @@ let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in {
def FMINNMVH : SInst<"vminnmv", "1.", "hQh">;
}

let ArchGuard = "defined(__aarch64__)" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {
// Permutation
def VTRN1H : SOpInst<"vtrn1", "...", "hQh", OP_TRN1>;
def VZIP1H : SOpInst<"vzip1", "...", "hQh", OP_ZIP1>;
Expand All @@ -1876,15 +1876,15 @@ let TargetGuard = "dotprod" in {
def DOT : SInst<"vdot", "..(<<)(<<)", "iQiUiQUi">;
def DOT_LANE : SOpInst<"vdot_lane", "..(<<)(<<q)I", "iUiQiQUi", OP_DOT_LN>;
}
let ArchGuard = "defined(__aarch64__)", TargetGuard = "dotprod" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "dotprod" in {
// Variants indexing into a 128-bit vector are A64 only.
def UDOT_LANEQ : SOpInst<"vdot_laneq", "..(<<)(<<Q)I", "iUiQiQUi", OP_DOT_LNQ> {
let isLaneQ = 1;
}
}

// v8.2-A FP16 fused multiply-add long instructions.
let ArchGuard = "defined(__aarch64__)", TargetGuard = "fp16fml" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "fp16fml" in {
def VFMLAL_LOW : SInst<"vfmlal_low", ">>..", "hQh">;
def VFMLSL_LOW : SInst<"vfmlsl_low", ">>..", "hQh">;
def VFMLAL_HIGH : SInst<"vfmlal_high", ">>..", "hQh">;
Expand Down Expand Up @@ -1918,7 +1918,7 @@ let TargetGuard = "i8mm" in {
def VUSDOT_LANE : SOpInst<"vusdot_lane", "..(<<U)(<<q)I", "iQi", OP_USDOT_LN>;
def VSUDOT_LANE : SOpInst<"vsudot_lane", "..(<<)(<<qU)I", "iQi", OP_SUDOT_LN>;

let ArchGuard = "defined(__aarch64__)" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)" in {
let isLaneQ = 1 in {
def VUSDOT_LANEQ : SOpInst<"vusdot_laneq", "..(<<U)(<<Q)I", "iQi", OP_USDOT_LNQ>;
def VSUDOT_LANEQ : SOpInst<"vsudot_laneq", "..(<<)(<<QU)I", "iQi", OP_SUDOT_LNQ>;
Expand Down Expand Up @@ -1986,7 +1986,7 @@ let TargetGuard = "v8.3a" in {

defm VCMLA_F32 : VCMLA_ROTS<"f", "uint64x1_t", "uint64x2_t">;
}
let ArchGuard = "defined(__aarch64__)", TargetGuard = "v8.3a" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "v8.3a" in {
def VCADDQ_ROT90_FP64 : SInst<"vcaddq_rot90", "QQQ", "d">;
def VCADDQ_ROT270_FP64 : SInst<"vcaddq_rot270", "QQQ", "d">;

Expand Down Expand Up @@ -2058,14 +2058,14 @@ let TargetGuard = "bf16" in {
def SCALAR_CVT_F32_BF16 : SOpInst<"vcvtah_f32", "(1F>)(1!)", "b", OP_CVT_F32_BF16>;
}

let ArchGuard = "!defined(__aarch64__)", TargetGuard = "bf16" in {
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16" in {
def VCVT_BF16_F32_A32_INTERNAL : WInst<"__a32_vcvt_bf16", "BQ", "f">;
def VCVT_BF16_F32_A32 : SOpInst<"vcvt_bf16", "BQ", "f", OP_VCVT_BF16_F32_A32>;
def VCVT_LOW_BF16_F32_A32 : SOpInst<"vcvt_low_bf16", "BQ", "Qf", OP_VCVT_BF16_F32_LO_A32>;
def VCVT_HIGH_BF16_F32_A32 : SOpInst<"vcvt_high_bf16", "BBQ", "Qf", OP_VCVT_BF16_F32_HI_A32>;
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "bf16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16" in {
def VCVT_LOW_BF16_F32_A64_INTERNAL : WInst<"__a64_vcvtq_low_bf16", "BQ", "Hf">;
def VCVT_LOW_BF16_F32_A64 : SOpInst<"vcvt_low_bf16", "BQ", "Qf", OP_VCVT_BF16_F32_LO_A64>;
def VCVT_HIGH_BF16_F32_A64 : SInst<"vcvt_high_bf16", "BBQ", "Qf">;
Expand All @@ -2077,22 +2077,22 @@ let ArchGuard = "defined(__aarch64__)", TargetGuard = "bf16" in {
def COPYQ_LANEQ_BF16 : IOpInst<"vcopy_laneq", "..I.I", "Qb", OP_COPY_LN>;
}

let ArchGuard = "!defined(__aarch64__)", TargetGuard = "bf16" in {
let ArchGuard = "!defined(__aarch64__) && !defined(__arm64ec__)", TargetGuard = "bf16" in {
let BigEndianSafe = 1 in {
defm VREINTERPRET_BF : REINTERPRET_CROSS_TYPES<
"csilUcUsUiUlhfPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQPcQPsQPl", "bQb">;
}
}

let ArchGuard = "defined(__aarch64__)", TargetGuard = "bf16" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "bf16" in {
let BigEndianSafe = 1 in {
defm VVREINTERPRET_BF : REINTERPRET_CROSS_TYPES<
"csilUcUsUiUlhfdPcPsPlQcQsQiQlQUcQUsQUiQUlQhQfQdQPcQPsQPlQPk", "bQb">;
}
}

// v8.9a/v9.4a LRCPC3 intrinsics
let ArchGuard = "defined(__aarch64__)", TargetGuard = "rcpc3" in {
let ArchGuard = "defined(__aarch64__) || defined(__arm64ec__)", TargetGuard = "rcpc3" in {
def VLDAP1_LANE : WInst<"vldap1_lane", ".(c*!).I", "QUlQlUlldQdPlQPl">;
def VSTL1_LANE : WInst<"vstl1_lane", "v*(.!)I", "QUlQlUlldQdPlQPl">;
}
6 changes: 2 additions & 4 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,7 @@ class InitializationSequence {
OverloadingResult FailedOverloadResult;

/// The candidate set created when initialization failed.
std::unique_ptr<OverloadCandidateSet> FailedCandidateSet;
OverloadCandidateSet FailedCandidateSet;

/// The incomplete type that caused a failure.
QualType FailedIncompleteType;
Expand Down Expand Up @@ -1403,9 +1403,7 @@ class InitializationSequence {
/// Retrieve a reference to the candidate set when overload
/// resolution fails.
OverloadCandidateSet &getFailedCandidateSet() {
assert(FailedCandidateSet &&
"this should have been allocated in the constructor!");
return *FailedCandidateSet;
return FailedCandidateSet;
}

/// Get the overloading result, for when the initialization
Expand Down
70 changes: 51 additions & 19 deletions clang/include/clang/Sema/Overload.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <utility>

namespace clang {
Expand Down Expand Up @@ -875,8 +874,7 @@ class Sema;
ConversionFixItGenerator Fix;

/// Viable - True to indicate that this overload candidate is viable.
LLVM_PREFERRED_TYPE(bool)
unsigned Viable : 1;
bool Viable : 1;

/// Whether this candidate is the best viable function, or tied for being
/// the best viable function.
Expand All @@ -885,14 +883,12 @@ class Sema;
/// was part of the ambiguity kernel: the minimal non-empty set of viable
/// candidates such that all elements of the ambiguity kernel are better
/// than all viable candidates not in the ambiguity kernel.
LLVM_PREFERRED_TYPE(bool)
unsigned Best : 1;
bool Best : 1;

/// IsSurrogate - True to indicate that this candidate is a
/// surrogate for a conversion to a function pointer or reference
/// (C++ [over.call.object]).
LLVM_PREFERRED_TYPE(bool)
unsigned IsSurrogate : 1;
bool IsSurrogate : 1;

/// IgnoreObjectArgument - True to indicate that the first
/// argument's conversion, which for this function represents the
Expand All @@ -901,20 +897,18 @@ class Sema;
/// implicit object argument is just a placeholder) or a
/// non-static member function when the call doesn't have an
/// object argument.
LLVM_PREFERRED_TYPE(bool)
unsigned IgnoreObjectArgument : 1;
bool IgnoreObjectArgument : 1;

/// True if the candidate was found using ADL.
LLVM_PREFERRED_TYPE(CallExpr::ADLCallKind)
unsigned IsADLCandidate : 1;
CallExpr::ADLCallKind IsADLCandidate : 1;

/// Whether this is a rewritten candidate, and if so, of what kind?
LLVM_PREFERRED_TYPE(OverloadCandidateRewriteKind)
unsigned RewriteKind : 2;

/// FailureKind - The reason why this candidate is not viable.
LLVM_PREFERRED_TYPE(OverloadFailureKind)
unsigned FailureKind : 5;
/// Actually an OverloadFailureKind.
unsigned char FailureKind;

/// The number of call arguments that were explicitly provided,
/// to be used while performing partial ordering of function templates.
Expand Down Expand Up @@ -978,9 +972,7 @@ class Sema;
private:
friend class OverloadCandidateSet;
OverloadCandidate()
: IsSurrogate(false),
IsADLCandidate(static_cast<unsigned>(CallExpr::NotADL)),
RewriteKind(CRK_None) {}
: IsSurrogate(false), IsADLCandidate(CallExpr::NotADL), RewriteKind(CRK_None) {}
};

/// OverloadCandidateSet - A set of overload candidates, used in C++
Expand Down Expand Up @@ -1078,16 +1070,51 @@ class Sema;
};

private:
SmallVector<OverloadCandidate, 4> Candidates;
llvm::SmallPtrSet<uintptr_t, 4> Functions;
SmallVector<OverloadCandidate, 16> Candidates;
llvm::SmallPtrSet<uintptr_t, 16> Functions;

// Allocator for ConversionSequenceLists. We store the first few of these
// inline to avoid allocation for small sets.
llvm::BumpPtrAllocator SlabAllocator;

SourceLocation Loc;
CandidateSetKind Kind;
OperatorRewriteInfo RewriteInfo;

constexpr static unsigned NumInlineBytes =
24 * sizeof(ImplicitConversionSequence);
unsigned NumInlineBytesUsed = 0;
alignas(void *) char InlineSpace[NumInlineBytes];

// Address space of the object being constructed.
LangAS DestAS = LangAS::Default;

/// If we have space, allocates from inline storage. Otherwise, allocates
/// from the slab allocator.
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
/// instead.
/// FIXME: Now that this only allocates ImplicitConversionSequences, do we
/// want to un-generalize this?
template <typename T>
T *slabAllocate(unsigned N) {
// It's simpler if this doesn't need to consider alignment.
static_assert(alignof(T) == alignof(void *),
"Only works for pointer-aligned types.");
static_assert(std::is_trivial<T>::value ||
std::is_same<ImplicitConversionSequence, T>::value,
"Add destruction logic to OverloadCandidateSet::clear().");

unsigned NBytes = sizeof(T) * N;
if (NBytes > NumInlineBytes - NumInlineBytesUsed)
return SlabAllocator.Allocate<T>(N);
char *FreeSpaceStart = InlineSpace + NumInlineBytesUsed;
assert(uintptr_t(FreeSpaceStart) % alignof(void *) == 0 &&
"Misaligned storage!");

NumInlineBytesUsed += NBytes;
return reinterpret_cast<T *>(FreeSpaceStart);
}

void destroyCandidates();

public:
Expand Down Expand Up @@ -1136,7 +1163,12 @@ class Sema;
ConversionSequenceList
allocateConversionSequences(unsigned NumConversions) {
ImplicitConversionSequence *Conversions =
new ImplicitConversionSequence[NumConversions];
slabAllocate<ImplicitConversionSequence>(NumConversions);

// Construct the new objects.
for (unsigned I = 0; I != NumConversions; ++I)
new (&Conversions[I]) ImplicitConversionSequence();

return ConversionSequenceList(Conversions, NumConversions);
}

Expand Down
81 changes: 47 additions & 34 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,14 @@ class PreferredTypeBuilder {
llvm::function_ref<QualType()> ComputeType;
};

struct SkipBodyInfo {
SkipBodyInfo() = default;
bool ShouldSkip = false;
bool CheckSameAsPrevious = false;
NamedDecl *Previous = nullptr;
NamedDecl *New = nullptr;
};

/// Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
Expand Down Expand Up @@ -429,6 +437,20 @@ enum class CXXSpecialMemberKind {
Invalid
};

/// The kind of conversion being performed.
enum class CheckedConversionKind {
/// An implicit conversion.
Implicit,
/// A C-style cast.
CStyleCast,
/// A functional-style cast.
FunctionalCast,
/// A cast other than a C-style cast.
OtherCast,
/// A conversion for an operand of a builtin overloaded operator.
ForBuiltinOverloadedOp
};

/// Sema - This implements semantic analysis and AST building for C.
/// \nosubgrouping
class Sema final : public SemaBase {
Expand Down Expand Up @@ -692,28 +714,27 @@ class Sema final : public SemaBase {
void checkTypeSupport(QualType Ty, SourceLocation Loc,
ValueDecl *D = nullptr);

/// The kind of conversion being performed.
enum CheckedConversionKind {
/// An implicit conversion.
CCK_ImplicitConversion,
/// A C-style cast.
CCK_CStyleCast,
/// A functional-style cast.
CCK_FunctionalCast,
/// A cast other than a C-style cast.
CCK_OtherCast,
/// A conversion for an operand of a builtin overloaded operator.
CCK_ForBuiltinOverloadedOp
};
// /// The kind of conversion being performed.
// enum CheckedConversionKind {
// /// An implicit conversion.
// CCK_ImplicitConversion,
// /// A C-style cast.
// CCK_CStyleCast,
// /// A functional-style cast.
// CCK_FunctionalCast,
// /// A cast other than a C-style cast.
// CCK_OtherCast,
// /// A conversion for an operand of a builtin overloaded operator.
// CCK_ForBuiltinOverloadedOp
// };

/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
ExprResult
ImpCastExprToType(Expr *E, QualType Type, CastKind CK,
ExprValueKind VK = VK_PRValue,
const CXXCastPath *BasePath = nullptr,
CheckedConversionKind CCK = CCK_ImplicitConversion);
ExprResult ImpCastExprToType(
Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_PRValue,
const CXXCastPath *BasePath = nullptr,
CheckedConversionKind CCK = CheckedConversionKind::Implicit);

/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding
/// to the conversion from scalar type ScalarTy to the Boolean type.
Expand Down Expand Up @@ -1773,8 +1794,9 @@ class Sema final : public SemaBase {

public:
static bool isCast(CheckedConversionKind CCK) {
return CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast ||
CCK == CCK_OtherCast;
return CCK == CheckedConversionKind::CStyleCast ||
CCK == CheckedConversionKind::FunctionalCast ||
CCK == CheckedConversionKind::OtherCast;
}

/// ActOnCXXNamedCast - Parse
Expand Down Expand Up @@ -2627,14 +2649,6 @@ class Sema final : public SemaBase {
return Entity->getOwningModule();
}

struct SkipBodyInfo {
SkipBodyInfo() = default;
bool ShouldSkip = false;
bool CheckSameAsPrevious = false;
NamedDecl *Previous = nullptr;
NamedDecl *New = nullptr;
};

DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr);

ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
Expand Down Expand Up @@ -6739,11 +6753,10 @@ class Sema final : public SemaBase {

bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType);

ExprResult
PerformImplicitConversion(Expr *From, QualType ToType,
const ImplicitConversionSequence &ICS,
AssignmentAction Action,
CheckedConversionKind CCK = CCK_ImplicitConversion);
ExprResult PerformImplicitConversion(
Expr *From, QualType ToType, const ImplicitConversionSequence &ICS,
AssignmentAction Action,
CheckedConversionKind CCK = CheckedConversionKind::Implicit);
ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence &SCS,
AssignmentAction Action,
Expand Down Expand Up @@ -7064,7 +7077,7 @@ class Sema final : public SemaBase {

ExprResult PerformQualificationConversion(
Expr *E, QualType Ty, ExprValueKind VK = VK_PRValue,
CheckedConversionKind CCK = CCK_ImplicitConversion);
CheckedConversionKind CCK = CheckedConversionKind::Implicit);

bool CanPerformCopyInitialization(const InitializedEntity &Entity,
ExprResult Init);
Expand Down
125 changes: 72 additions & 53 deletions clang/lib/Analysis/ExprMutationAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,10 @@ template <> struct NodeID<Decl> { static constexpr StringRef value = "decl"; };
constexpr StringRef NodeID<Expr>::value;
constexpr StringRef NodeID<Decl>::value;

template <class T, class F = const Stmt *(ExprMutationAnalyzer::*)(const T *)>
template <class T,
class F = const Stmt *(ExprMutationAnalyzer::Analyzer::*)(const T *)>
const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,
ExprMutationAnalyzer *Analyzer, F Finder) {
ExprMutationAnalyzer::Analyzer *Analyzer, F Finder) {
const StringRef ID = NodeID<T>::value;
for (const auto &Nodes : Matches) {
if (const Stmt *S = (Analyzer->*Finder)(Nodes.getNodeAs<T>(ID)))
Expand All @@ -199,33 +200,37 @@ const Stmt *tryEachMatch(ArrayRef<ast_matchers::BoundNodes> Matches,

} // namespace

const Stmt *ExprMutationAnalyzer::findMutation(const Expr *Exp) {
return findMutationMemoized(Exp,
{&ExprMutationAnalyzer::findDirectMutation,
&ExprMutationAnalyzer::findMemberMutation,
&ExprMutationAnalyzer::findArrayElementMutation,
&ExprMutationAnalyzer::findCastMutation,
&ExprMutationAnalyzer::findRangeLoopMutation,
&ExprMutationAnalyzer::findReferenceMutation,
&ExprMutationAnalyzer::findFunctionArgMutation},
Results);
const Stmt *ExprMutationAnalyzer::Analyzer::findMutation(const Expr *Exp) {
return findMutationMemoized(
Exp,
{&ExprMutationAnalyzer::Analyzer::findDirectMutation,
&ExprMutationAnalyzer::Analyzer::findMemberMutation,
&ExprMutationAnalyzer::Analyzer::findArrayElementMutation,
&ExprMutationAnalyzer::Analyzer::findCastMutation,
&ExprMutationAnalyzer::Analyzer::findRangeLoopMutation,
&ExprMutationAnalyzer::Analyzer::findReferenceMutation,
&ExprMutationAnalyzer::Analyzer::findFunctionArgMutation},
Memorized.Results);
}

const Stmt *ExprMutationAnalyzer::findMutation(const Decl *Dec) {
return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findMutation);
const Stmt *ExprMutationAnalyzer::Analyzer::findMutation(const Decl *Dec) {
return tryEachDeclRef(Dec, &ExprMutationAnalyzer::Analyzer::findMutation);
}

const Stmt *ExprMutationAnalyzer::findPointeeMutation(const Expr *Exp) {
return findMutationMemoized(Exp, {/*TODO*/}, PointeeResults);
const Stmt *
ExprMutationAnalyzer::Analyzer::findPointeeMutation(const Expr *Exp) {
return findMutationMemoized(Exp, {/*TODO*/}, Memorized.PointeeResults);
}

const Stmt *ExprMutationAnalyzer::findPointeeMutation(const Decl *Dec) {
return tryEachDeclRef(Dec, &ExprMutationAnalyzer::findPointeeMutation);
const Stmt *
ExprMutationAnalyzer::Analyzer::findPointeeMutation(const Decl *Dec) {
return tryEachDeclRef(Dec,
&ExprMutationAnalyzer::Analyzer::findPointeeMutation);
}

const Stmt *ExprMutationAnalyzer::findMutationMemoized(
const Stmt *ExprMutationAnalyzer::Analyzer::findMutationMemoized(
const Expr *Exp, llvm::ArrayRef<MutationFinder> Finders,
ResultMap &MemoizedResults) {
Memoized::ResultMap &MemoizedResults) {
const auto Memoized = MemoizedResults.find(Exp);
if (Memoized != MemoizedResults.end())
return Memoized->second;
Expand All @@ -241,8 +246,9 @@ const Stmt *ExprMutationAnalyzer::findMutationMemoized(
return MemoizedResults[Exp] = nullptr;
}

const Stmt *ExprMutationAnalyzer::tryEachDeclRef(const Decl *Dec,
MutationFinder Finder) {
const Stmt *
ExprMutationAnalyzer::Analyzer::tryEachDeclRef(const Decl *Dec,
MutationFinder Finder) {
const auto Refs = match(
findAll(
declRefExpr(to(
Expand All @@ -261,8 +267,9 @@ const Stmt *ExprMutationAnalyzer::tryEachDeclRef(const Decl *Dec,
return nullptr;
}

bool ExprMutationAnalyzer::isUnevaluated(const Stmt *Exp, const Stmt &Stm,
ASTContext &Context) {
bool ExprMutationAnalyzer::Analyzer::isUnevaluated(const Stmt *Exp,
const Stmt &Stm,
ASTContext &Context) {
return selectFirst<Stmt>(
NodeID<Expr>::value,
match(
Expand Down Expand Up @@ -293,33 +300,36 @@ bool ExprMutationAnalyzer::isUnevaluated(const Stmt *Exp, const Stmt &Stm,
Stm, Context)) != nullptr;
}

bool ExprMutationAnalyzer::isUnevaluated(const Expr *Exp) {
bool ExprMutationAnalyzer::Analyzer::isUnevaluated(const Expr *Exp) {
return isUnevaluated(Exp, Stm, Context);
}

const Stmt *
ExprMutationAnalyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
return tryEachMatch<Expr>(Matches, this, &ExprMutationAnalyzer::findMutation);
ExprMutationAnalyzer::Analyzer::findExprMutation(ArrayRef<BoundNodes> Matches) {
return tryEachMatch<Expr>(Matches, this,
&ExprMutationAnalyzer::Analyzer::findMutation);
}

const Stmt *
ExprMutationAnalyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
return tryEachMatch<Decl>(Matches, this, &ExprMutationAnalyzer::findMutation);
ExprMutationAnalyzer::Analyzer::findDeclMutation(ArrayRef<BoundNodes> Matches) {
return tryEachMatch<Decl>(Matches, this,
&ExprMutationAnalyzer::Analyzer::findMutation);
}

const Stmt *ExprMutationAnalyzer::findExprPointeeMutation(
const Stmt *ExprMutationAnalyzer::Analyzer::findExprPointeeMutation(
ArrayRef<ast_matchers::BoundNodes> Matches) {
return tryEachMatch<Expr>(Matches, this,
&ExprMutationAnalyzer::findPointeeMutation);
return tryEachMatch<Expr>(
Matches, this, &ExprMutationAnalyzer::Analyzer::findPointeeMutation);
}

const Stmt *ExprMutationAnalyzer::findDeclPointeeMutation(
const Stmt *ExprMutationAnalyzer::Analyzer::findDeclPointeeMutation(
ArrayRef<ast_matchers::BoundNodes> Matches) {
return tryEachMatch<Decl>(Matches, this,
&ExprMutationAnalyzer::findPointeeMutation);
return tryEachMatch<Decl>(
Matches, this, &ExprMutationAnalyzer::Analyzer::findPointeeMutation);
}

const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) {
// LHS of any assignment operators.
const auto AsAssignmentLhs =
binaryOperator(isAssignmentOperator(), hasLHS(canResolveToExpr(Exp)));
Expand Down Expand Up @@ -426,7 +436,7 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
const auto AsNonConstRefReturn =
returnStmt(hasReturnValue(canResolveToExpr(Exp)));

// It is used as a non-const-reference for initalizing a range-for loop.
// It is used as a non-const-reference for initializing a range-for loop.
const auto AsNonConstRefRangeInit = cxxForRangeStmt(hasRangeInit(declRefExpr(
allOf(canResolveToExpr(Exp), hasType(nonConstReferenceType())))));

Expand All @@ -443,7 +453,8 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) {
return selectFirst<Stmt>("stmt", Matches);
}

const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findMemberMutation(const Expr *Exp) {
// Check whether any member of 'Exp' is mutated.
const auto MemberExprs = match(
findAll(expr(anyOf(memberExpr(hasObjectExpression(canResolveToExpr(Exp))),
Expand All @@ -456,7 +467,8 @@ const Stmt *ExprMutationAnalyzer::findMemberMutation(const Expr *Exp) {
return findExprMutation(MemberExprs);
}

const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findArrayElementMutation(const Expr *Exp) {
// Check whether any element of an array is mutated.
const auto SubscriptExprs = match(
findAll(arraySubscriptExpr(
Expand All @@ -469,7 +481,7 @@ const Stmt *ExprMutationAnalyzer::findArrayElementMutation(const Expr *Exp) {
return findExprMutation(SubscriptExprs);
}

const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) {
const Stmt *ExprMutationAnalyzer::Analyzer::findCastMutation(const Expr *Exp) {
// If the 'Exp' is explicitly casted to a non-const reference type the
// 'Exp' is considered to be modified.
const auto ExplicitCast =
Expand Down Expand Up @@ -504,7 +516,8 @@ const Stmt *ExprMutationAnalyzer::findCastMutation(const Expr *Exp) {
return findExprMutation(Calls);
}

const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findRangeLoopMutation(const Expr *Exp) {
// Keep the ordering for the specific initialization matches to happen first,
// because it is cheaper to match all potential modifications of the loop
// variable.
Expand Down Expand Up @@ -567,7 +580,8 @@ const Stmt *ExprMutationAnalyzer::findRangeLoopMutation(const Expr *Exp) {
return findDeclMutation(LoopVars);
}

const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findReferenceMutation(const Expr *Exp) {
// Follow non-const reference returned by `operator*()` of move-only classes.
// These are typically smart pointers with unique ownership so we treat
// mutation of pointee as mutation of the smart pointer itself.
Expand Down Expand Up @@ -599,7 +613,8 @@ const Stmt *ExprMutationAnalyzer::findReferenceMutation(const Expr *Exp) {
return findDeclMutation(Refs);
}

const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) {
const Stmt *
ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) {
const auto NonConstRefParam = forEachArgumentWithParam(
canResolveToExpr(Exp),
parmVarDecl(hasType(nonConstReferenceType())).bind("parm"));
Expand Down Expand Up @@ -637,10 +652,9 @@ const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) {
if (const auto *RefType = ParmType->getAs<RValueReferenceType>()) {
if (!RefType->getPointeeType().getQualifiers() &&
RefType->getPointeeType()->getAs<TemplateTypeParmType>()) {
std::unique_ptr<FunctionParmMutationAnalyzer> &Analyzer =
FuncParmAnalyzer[Func];
if (!Analyzer)
Analyzer.reset(new FunctionParmMutationAnalyzer(*Func, Context));
FunctionParmMutationAnalyzer *Analyzer =
FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
*Func, Context, Memorized);
if (Analyzer->findMutation(Parm))
return Exp;
continue;
Expand All @@ -653,13 +667,15 @@ const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) {
}

FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer(
const FunctionDecl &Func, ASTContext &Context)
: BodyAnalyzer(*Func.getBody(), Context) {
const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized)
: BodyAnalyzer(*Func.getBody(), Context, Memorized) {
if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(&Func)) {
// CXXCtorInitializer might also mutate Param but they're not part of
// function body, check them eagerly here since they're typically trivial.
for (const CXXCtorInitializer *Init : Ctor->inits()) {
ExprMutationAnalyzer InitAnalyzer(*Init->getInit(), Context);
ExprMutationAnalyzer::Analyzer InitAnalyzer(*Init->getInit(), Context,
Memorized);
for (const ParmVarDecl *Parm : Ctor->parameters()) {
if (Results.contains(Parm))
continue;
Expand All @@ -675,11 +691,14 @@ FunctionParmMutationAnalyzer::findMutation(const ParmVarDecl *Parm) {
const auto Memoized = Results.find(Parm);
if (Memoized != Results.end())
return Memoized->second;

// To handle call A -> call B -> call A. Assume parameters of A is not mutated
// before analyzing parameters of A. Then when analyzing the second "call A",
// FunctionParmMutationAnalyzer can use this memoized value to avoid infinite
// recursion.
Results[Parm] = nullptr;
if (const Stmt *S = BodyAnalyzer.findMutation(Parm))
return Results[Parm] = S;

return Results[Parm] = nullptr;
return Results[Parm];
}

} // namespace clang
11 changes: 10 additions & 1 deletion clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,11 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
// below them can initialize the same object (or part of it).
if (isa<CXXConstructExpr>(E) || isa<CallExpr>(E) || isa<LambdaExpr>(E) ||
isa<CXXDefaultArgExpr>(E) || isa<CXXDefaultInitExpr>(E) ||
isa<CXXStdInitializerListExpr>(E)) {
isa<CXXStdInitializerListExpr>(E) ||
// We treat `BuiltinBitCastExpr` as an "original initializer" too as
// it may not even be casting from a record type -- and even if it is,
// the two objects are in general of unrelated type.
isa<BuiltinBitCastExpr>(E)) {
return;
}
if (auto *Op = dyn_cast<BinaryOperator>(E);
Expand Down Expand Up @@ -470,6 +474,11 @@ class ResultObjectVisitor : public RecursiveASTVisitor<ResultObjectVisitor> {
return;
}

if (auto *SE = dyn_cast<StmtExpr>(E)) {
PropagateResultObject(cast<Expr>(SE->getSubStmt()->body_back()), Loc);
return;
}

// All other expression nodes that propagate a record prvalue should have
// exactly one child.
SmallVector<Stmt *, 1> Children(E->child_begin(), E->child_end());
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
HasLegalHalfType = true;

FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access");
FastUnalignedAccess = llvm::is_contained(Features, "+unaligned-scalar-mem") &&
llvm::is_contained(Features, "+unaligned-vector-mem");

if (llvm::is_contained(Features, "+experimental"))
HasExperimental = true;
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3436,6 +3436,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Builder.CreateAssumption(ConstantInt::getTrue(getLLVMContext()), {OBD});
return RValue::get(nullptr);
}
case Builtin::BI__builtin_allow_runtime_check: {
StringRef Kind =
cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())->getString();
LLVMContext &Ctx = CGM.getLLVMContext();
llvm::Value *Allow = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::allow_runtime_check),
llvm::MetadataAsValue::get(Ctx, llvm::MDString::get(Ctx, Kind)));
return RValue::get(Allow);
}
case Builtin::BI__arithmetic_fence: {
// Create the builtin call if FastMath is selected, and the target
// supports the builtin, otherwise just return the argument.
Expand Down
16 changes: 11 additions & 5 deletions clang/lib/Driver/ToolChains/Arch/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,10 @@ static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,
<< A->getSpelling() << Mcpu;
}

if (llvm::RISCV::hasFastUnalignedAccess(Mcpu))
Features.push_back("+fast-unaligned-access");
if (llvm::RISCV::hasFastUnalignedAccess(Mcpu)) {
Features.push_back("+unaligned-scalar-mem");
Features.push_back("+unaligned-vector-mem");
}
}

void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Expand Down Expand Up @@ -168,12 +170,16 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
}

// Android requires fast unaligned access on RISCV64.
if (Triple.isAndroid())
Features.push_back("+fast-unaligned-access");
if (Triple.isAndroid()) {
Features.push_back("+unaligned-scalar-mem");
Features.push_back("+unaligned-vector-mem");
}

// -mstrict-align is default, unless -mno-strict-align is specified.
AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
options::OPT_mstrict_align, "fast-unaligned-access");
options::OPT_mstrict_align, "unaligned-scalar-mem");
AddTargetFeature(Args, Features, options::OPT_mno_strict_align,
options::OPT_mstrict_align, "unaligned-vector-mem");

// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5331,7 +5331,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,

stripTypeAttributesOffDeclSpec(attrs, DS, TUK);

Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
if (!Name && TUK == Sema::TUK_Definition && Tok.is(tok::l_brace) &&
NextToken().is(tok::identifier))
SkipBody = Actions.shouldSkipAnonEnumBody(getCurScope(),
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2092,7 +2092,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TypeResult TypeResult = true; // invalid

bool Owned = false;
Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
if (TemplateId) {
// Explicit specialization, class template partial specialization,
// or explicit instantiation.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Parse/ParseObjc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ Decl *Parser::ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc,
Actions.ActOnTypedefedProtocols(protocols, protocolLocs,
superClassId, superClassLoc);

Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
ObjCInterfaceDecl *ClsType = Actions.ActOnStartClassInterface(
getCurScope(), AtLoc, nameId, nameLoc, typeParameterList, superClassId,
superClassLoc, typeArgs,
Expand Down Expand Up @@ -2133,7 +2133,7 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
/*consumeLastToken=*/true))
return nullptr;

Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
ObjCProtocolDecl *ProtoType = Actions.ActOnStartProtocolInterface(
AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(),
ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1441,7 +1441,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,

// Tell the actions module that we have entered a function definition with the
// specified Declarator for the function.
Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
TemplateInfo.TemplateParams
? *TemplateInfo.TemplateParams
Expand Down
73 changes: 35 additions & 38 deletions clang/lib/Sema/SemaCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ namespace {
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}

void checkObjCConversion(Sema::CheckedConversionKind CCK) {
void checkObjCConversion(CheckedConversionKind CCK) {
assert(Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers());

Expr *src = SrcExpr.get();
Expand Down Expand Up @@ -248,18 +248,14 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExp
CastKind &Kind,
CXXCastPath &BasePath);

static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange,
unsigned &msg, CastKind &Kind,
bool ListInitialization);
static TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
CheckedConversionKind CCK, SourceRange OpRange,
unsigned &msg, CastKind &Kind, bool ListInitialization);
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange,
unsigned &msg, CastKind &Kind,
CXXCastPath &BasePath,
QualType DestType, CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath,
bool ListInitialization);
static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
Expand Down Expand Up @@ -1223,7 +1219,7 @@ void CastOperation::CheckReinterpretCast() {

if (isValidCast(tcr)) {
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
checkObjCConversion(Sema::CCK_OtherCast);
checkObjCConversion(CheckedConversionKind::OtherCast);
DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange);

if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType))
Expand Down Expand Up @@ -1274,9 +1270,9 @@ void CastOperation::CheckStaticCast() {
}

unsigned msg = diag::err_bad_cxx_cast_generic;
TryCastResult tcr
= TryStaticCast(Self, SrcExpr, DestType, Sema::CCK_OtherCast, OpRange, msg,
Kind, BasePath, /*ListInitialization=*/false);
TryCastResult tcr =
TryStaticCast(Self, SrcExpr, DestType, CheckedConversionKind::OtherCast,
OpRange, msg, Kind, BasePath, /*ListInitialization=*/false);
if (tcr != TC_Success && msg != 0) {
if (SrcExpr.isInvalid())
return;
Expand All @@ -1296,7 +1292,7 @@ void CastOperation::CheckStaticCast() {
if (Kind == CK_BitCast)
checkCastAlign();
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers())
checkObjCConversion(Sema::CCK_OtherCast);
checkObjCConversion(CheckedConversionKind::OtherCast);
} else {
SrcExpr = ExprError();
}
Expand All @@ -1317,14 +1313,13 @@ static bool IsAddressSpaceConversion(QualType SrcType, QualType DestType) {
/// possible. If @p CStyle, ignore access restrictions on hierarchy casting
/// and casting away constness.
static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
Sema::CheckedConversionKind CCK,
QualType DestType, CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, CXXCastPath &BasePath,
bool ListInitialization) {
// Determine whether we have the semantics of a C-style cast.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
bool CStyle = (CCK == CheckedConversionKind::CStyleCast ||
CCK == CheckedConversionKind::FunctionalCast);

// The order the tests is not entirely arbitrary. There is one conversion
// that can be handled in two different ways. Given:
Expand Down Expand Up @@ -1884,11 +1879,11 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
///
/// An expression e can be explicitly converted to a type T using a
/// @c static_cast if the declaration "T t(e);" is well-formed [...].
TryCastResult
TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
Sema::CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, bool ListInitialization) {
TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType,
CheckedConversionKind CCK,
SourceRange OpRange, unsigned &msg,
CastKind &Kind, bool ListInitialization) {
if (DestType->isRecordType()) {
if (Self.RequireCompleteType(OpRange.getBegin(), DestType,
diag::err_bad_cast_incomplete) ||
Expand All @@ -1900,13 +1895,14 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
}

InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType);
InitializationKind InitKind
= (CCK == Sema::CCK_CStyleCast)
? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange,
ListInitialization)
: (CCK == Sema::CCK_FunctionalCast)
? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization)
: InitializationKind::CreateCast(OpRange);
InitializationKind InitKind =
(CCK == CheckedConversionKind::CStyleCast)
? InitializationKind::CreateCStyleCast(OpRange.getBegin(), OpRange,
ListInitialization)
: (CCK == CheckedConversionKind::FunctionalCast)
? InitializationKind::CreateFunctionalCast(OpRange,
ListInitialization)
: InitializationKind::CreateCast(OpRange);
Expr *SrcExprRaw = SrcExpr.get();
// FIXME: Per DR242, we should check for an implicit conversion sequence
// or for a constructor that could be invoked by direct-initialization
Expand All @@ -1918,8 +1914,8 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType,
// There is no other way that works.
// On the other hand, if we're checking a C-style cast, we've still got
// the reinterpret_cast way.
bool CStyle
= (CCK == Sema::CCK_CStyleCast || CCK == Sema::CCK_FunctionalCast);
bool CStyle = (CCK == CheckedConversionKind::CStyleCast ||
CCK == CheckedConversionKind::FunctionalCast);
if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType()))
return TC_NotApplicable;

Expand Down Expand Up @@ -2814,8 +2810,9 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle,
if (isValidCast(tcr))
Kind = CK_NoOp;

Sema::CheckedConversionKind CCK =
FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast;
CheckedConversionKind CCK = FunctionalStyle
? CheckedConversionKind::FunctionalCast
: CheckedConversionKind::CStyleCast;
if (tcr == TC_NotApplicable) {
tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg,
Kind);
Expand Down Expand Up @@ -3201,7 +3198,7 @@ void CastOperation::CheckCStyleCast() {

// ARC imposes extra restrictions on casts.
if (Self.getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) {
checkObjCConversion(Sema::CCK_CStyleCast);
checkObjCConversion(CheckedConversionKind::CStyleCast);
if (SrcExpr.isInvalid())
return;

Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3233,6 +3233,17 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
if (BuiltinCountZeroBitsGeneric(*this, TheCall))
return ExprError();
break;

case Builtin::BI__builtin_allow_runtime_check: {
Expr *Arg = TheCall->getArg(0);
// Check if the argument is a string literal.
if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) {
Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal)
<< Arg->getSourceRange();
return ExprError();
}
break;
}
}

if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall))
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3037,7 +3037,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {

if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) {
Sema::SkipBodyInfo SkipBody;
SkipBodyInfo SkipBody;
S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody);

// If we're skipping this definition, drop the "alias" attribute.
Expand Down Expand Up @@ -19999,7 +19999,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
Val, EnumVal);
}

Sema::SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II,
SourceLocation IILoc) {
if (!(getLangOpts().Modules || getLangOpts().ModulesLocalVisibility) ||
!getLangOpts().CPlusPlus)
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10177,8 +10177,9 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
// diagnostics and just checking for errors, e.g., during overload
// resolution, return Incompatible to indicate the failure.
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
CheckObjCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
Diagnose, DiagnoseCFAudited) != ACR_okay) {
CheckObjCConversion(SourceRange(), Ty, E,
CheckedConversionKind::Implicit, Diagnose,
DiagnoseCFAudited) != ACR_okay) {
if (!Diagnose)
return Incompatible;
}
Expand Down Expand Up @@ -12899,14 +12900,15 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
Expr *E = LHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCConversion(SourceRange(), RHSType, E,
CCK_ImplicitConversion);
CheckedConversionKind::Implicit);
LHS = ImpCastExprToType(E, RHSType,
RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
}
else {
Expr *E = RHS.get();
if (getLangOpts().ObjCAutoRefCount)
CheckObjCConversion(SourceRange(), LHSType, E, CCK_ImplicitConversion,
CheckObjCConversion(SourceRange(), LHSType, E,
CheckedConversionKind::Implicit,
/*Diagnose=*/true,
/*DiagnoseCFAudited=*/false, Opc);
RHS = ImpCastExprToType(E, LHSType,
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4250,7 +4250,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
AssignmentAction Action,
CheckedConversionKind CCK) {
// C++ [over.match.oper]p7: [...] operands of class type are converted [...]
if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType())
if (CCK == CheckedConversionKind::ForBuiltinOverloadedOp &&
!From->getType()->isRecordType())
return From;

switch (ICS.getKind()) {
Expand Down Expand Up @@ -4311,7 +4312,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
// C++ [over.match.oper]p7:
// [...] the second standard conversion sequence of a user-defined
// conversion sequence is not applied.
if (CCK == CCK_ForBuiltinOverloadedOp)
if (CCK == CheckedConversionKind::ForBuiltinOverloadedOp)
return From;

return PerformImplicitConversion(From, ToType, ICS.UserDefined.After,
Expand Down Expand Up @@ -4352,7 +4353,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
const StandardConversionSequence& SCS,
AssignmentAction Action,
CheckedConversionKind CCK) {
bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast);
bool CStyle = (CCK == CheckedConversionKind::CStyleCast ||
CCK == CheckedConversionKind::FunctionalCast);

// Overall FIXME: we are recomputing too many types here and doing far too
// much extra work. What this means is that we need to keep track of more
Expand Down
45 changes: 23 additions & 22 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3745,22 +3745,22 @@ bool Sema::isKnownName(StringRef name) {

template <typename DiagBuilderT>
static void addFixitForObjCARCConversion(
Sema &S, DiagBuilderT &DiagB, Sema::CheckedConversionKind CCK,
Sema &S, DiagBuilderT &DiagB, CheckedConversionKind CCK,
SourceLocation afterLParen, QualType castType, Expr *castExpr,
Expr *realCast, const char *bridgeKeyword, const char *CFBridgeName) {
// We handle C-style and implicit casts here.
switch (CCK) {
case Sema::CCK_ImplicitConversion:
case Sema::CCK_ForBuiltinOverloadedOp:
case Sema::CCK_CStyleCast:
case Sema::CCK_OtherCast:
case CheckedConversionKind::Implicit:
case CheckedConversionKind::ForBuiltinOverloadedOp:
case CheckedConversionKind::CStyleCast:
case CheckedConversionKind::OtherCast:
break;
case Sema::CCK_FunctionalCast:
case CheckedConversionKind::FunctionalCast:
return;
}

if (CFBridgeName) {
if (CCK == Sema::CCK_OtherCast) {
if (CCK == CheckedConversionKind::OtherCast) {
if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
SourceRange range(NCE->getOperatorLoc(),
NCE->getAngleBrackets().getEnd());
Expand Down Expand Up @@ -3805,9 +3805,9 @@ static void addFixitForObjCARCConversion(
return;
}

if (CCK == Sema::CCK_CStyleCast) {
if (CCK == CheckedConversionKind::CStyleCast) {
DiagB.AddFixItHint(FixItHint::CreateInsertion(afterLParen, bridgeKeyword));
} else if (CCK == Sema::CCK_OtherCast) {
} else if (CCK == CheckedConversionKind::OtherCast) {
if (const CXXNamedCastExpr *NCE = dyn_cast<CXXNamedCastExpr>(realCast)) {
std::string castCode = "(";
castCode += bridgeKeyword;
Expand Down Expand Up @@ -3866,12 +3866,12 @@ static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T,
return nullptr;
}

static void
diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
QualType castType, ARCConversionTypeClass castACTC,
Expr *castExpr, Expr *realCast,
ARCConversionTypeClass exprACTC,
Sema::CheckedConversionKind CCK) {
static void diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
QualType castType,
ARCConversionTypeClass castACTC,
Expr *castExpr, Expr *realCast,
ARCConversionTypeClass exprACTC,
CheckedConversionKind CCK) {
SourceLocation loc =
(castRange.isValid() ? castRange.getBegin() : castExpr->getExprLoc());

Expand Down Expand Up @@ -3927,7 +3927,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
auto DiagB = (CCK != Sema::CCK_OtherCast)
auto DiagB = (CCK != CheckedConversionKind::OtherCast)
? S.Diag(noteLoc, diag::note_arc_bridge)
: S.Diag(noteLoc, diag::note_arc_cstyle_bridge);

Expand All @@ -3937,7 +3937,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
}
if (CreateRule != ACC_plusZero)
{
auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
auto DiagB = (CCK == CheckedConversionKind::OtherCast && !br)
? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_transfer)
<< castExprType
: S.Diag(br ? castExpr->getExprLoc() : noteLoc,
Expand Down Expand Up @@ -3968,7 +3968,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
assert(CreateRule != ACC_bottom && "This cast should already be accepted.");
if (CreateRule != ACC_plusOne)
{
auto DiagB = (CCK != Sema::CCK_OtherCast)
auto DiagB = (CCK != CheckedConversionKind::OtherCast)
? S.Diag(noteLoc, diag::note_arc_bridge)
: S.Diag(noteLoc, diag::note_arc_cstyle_bridge);
addFixitForObjCARCConversion(S, DiagB, CCK, afterLParen,
Expand All @@ -3977,7 +3977,7 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
}
if (CreateRule != ACC_plusZero)
{
auto DiagB = (CCK == Sema::CCK_OtherCast && !br)
auto DiagB = (CCK == CheckedConversionKind::OtherCast && !br)
? S.Diag(noteLoc, diag::note_arc_cstyle_bridge_retained)
<< castType
: S.Diag(br ? castExpr->getExprLoc() : noteLoc,
Expand Down Expand Up @@ -4403,7 +4403,8 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType,
// Check for viability and report error if casting an rvalue to a
// life-time qualifier.
if (castACTC == ACTC_retainable &&
(CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
(CCK == CheckedConversionKind::CStyleCast ||
CCK == CheckedConversionKind::OtherCast) &&
castType != castExprType) {
const Type *DT = castType.getTypePtr();
QualType QDT = castType;
Expand Down Expand Up @@ -4517,11 +4518,11 @@ void Sema::diagnoseARCUnbridgedCast(Expr *e) {
if (CStyleCastExpr *cast = dyn_cast<CStyleCastExpr>(realCast)) {
castRange = SourceRange(cast->getLParenLoc(), cast->getRParenLoc());
castType = cast->getTypeAsWritten();
CCK = CCK_CStyleCast;
CCK = CheckedConversionKind::CStyleCast;
} else if (ExplicitCastExpr *cast = dyn_cast<ExplicitCastExpr>(realCast)) {
castRange = cast->getTypeInfoAsWritten()->getTypeLoc().getSourceRange();
castType = cast->getTypeAsWritten();
CCK = CCK_OtherCast;
CCK = CheckedConversionKind::OtherCast;
} else {
llvm_unreachable("Unexpected ImplicitCastExpr");
}
Expand Down
36 changes: 17 additions & 19 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6114,8 +6114,7 @@ InitializationSequence::InitializationSequence(
Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind,
MultiExprArg Args, bool TopLevelOfInitList, bool TreatUnavailableAsInvalid)
: FailedOverloadResult(OR_Success),
FailedCandidateSet(new OverloadCandidateSet(
Kind.getLocation(), OverloadCandidateSet::CSK_Normal)) {
FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList,
TreatUnavailableAsInvalid);
}
Expand Down Expand Up @@ -9058,11 +9057,11 @@ ExprResult InitializationSequence::Perform(Sema &S,
}
}

Sema::CheckedConversionKind CCK
= Kind.isCStyleCast()? Sema::CCK_CStyleCast
: Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
: Kind.isExplicitCast()? Sema::CCK_OtherCast
: Sema::CCK_ImplicitConversion;
CheckedConversionKind CCK =
Kind.isCStyleCast() ? CheckedConversionKind::CStyleCast
: Kind.isFunctionalCast() ? CheckedConversionKind::FunctionalCast
: Kind.isExplicitCast() ? CheckedConversionKind::OtherCast
: CheckedConversionKind::Implicit;
ExprResult CurInitExprRes =
S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
getAssignmentAction(Entity), CCK);
Expand Down Expand Up @@ -9736,7 +9735,7 @@ bool InitializationSequence::Diagnose(Sema &S,
switch (FailedOverloadResult) {
case OR_Ambiguous:

FailedCandidateSet->NoteCandidates(
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
Failure == FK_UserConversionOverloadFailed
Expand All @@ -9750,8 +9749,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;

case OR_No_Viable_Function: {
auto Cands =
FailedCandidateSet->CompleteCandidates(S, OCD_AllCandidates, Args);
auto Cands = FailedCandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args);
if (!S.RequireCompleteType(Kind.getLocation(),
DestType.getNonReferenceType(),
diag::err_typecheck_nonviable_condition_incomplete,
Expand All @@ -9761,13 +9759,13 @@ bool InitializationSequence::Diagnose(Sema &S,
<< OnlyArg->getType() << Args[0]->getSourceRange()
<< DestType.getNonReferenceType();

FailedCandidateSet->NoteCandidates(S, Args, Cands);
FailedCandidateSet.NoteCandidates(S, Args, Cands);
break;
}
case OR_Deleted: {
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl =
FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);

StringLiteral *Msg = Best->Function->getDeletedMessage();
S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function)
Expand Down Expand Up @@ -9951,7 +9949,7 @@ bool InitializationSequence::Diagnose(Sema &S,
// bad.
switch (FailedOverloadResult) {
case OR_Ambiguous:
FailedCandidateSet->NoteCandidates(
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(Kind.getLocation(),
S.PDiag(diag::err_ovl_ambiguous_init)
<< DestType << ArgsRange),
Expand Down Expand Up @@ -10005,7 +10003,7 @@ bool InitializationSequence::Diagnose(Sema &S,
break;
}

FailedCandidateSet->NoteCandidates(
FailedCandidateSet.NoteCandidates(
PartialDiagnosticAt(
Kind.getLocation(),
S.PDiag(diag::err_ovl_no_viable_function_in_init)
Expand All @@ -10015,8 +10013,8 @@ bool InitializationSequence::Diagnose(Sema &S,

case OR_Deleted: {
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl =
FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
if (Ovl != OR_Deleted) {
S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init)
<< DestType << ArgsRange;
Expand Down Expand Up @@ -10095,8 +10093,8 @@ bool InitializationSequence::Diagnose(Sema &S,
S.Diag(Kind.getLocation(), diag::err_selected_explicit_constructor)
<< Args[0]->getSourceRange();
OverloadCandidateSet::iterator Best;
OverloadingResult Ovl =
FailedCandidateSet->BestViableFunction(S, Kind.getLocation(), Best);
OverloadingResult Ovl
= FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best);
(void)Ovl;
assert(Ovl == OR_Success && "Inconsistent overload resolution");
CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
Expand Down
31 changes: 15 additions & 16 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1057,14 +1057,17 @@ bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed(

void OverloadCandidateSet::destroyCandidates() {
for (iterator i = begin(), e = end(); i != e; ++i) {
delete[] i->Conversions.data();
for (auto &C : i->Conversions)
C.~ImplicitConversionSequence();
if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction)
i->DeductionFailure.Destroy();
}
}

void OverloadCandidateSet::clear(CandidateSetKind CSK) {
destroyCandidates();
SlabAllocator.Reset();
NumInlineBytesUsed = 0;
Candidates.clear();
Functions.clear();
Kind = CSK;
Expand Down Expand Up @@ -6980,7 +6983,7 @@ void Sema::AddOverloadCandidate(
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = static_cast<unsigned>(IsADLCandidate);
Candidate.IsADLCandidate = IsADLCandidate;
Candidate.IgnoreObjectArgument = false;
Candidate.ExplicitCallArguments = Args.size();

Expand Down Expand Up @@ -7812,7 +7815,7 @@ void Sema::AddTemplateOverloadCandidate(
Candidate.RewriteKind =
CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO);
Candidate.IsSurrogate = false;
Candidate.IsADLCandidate = static_cast<unsigned>(IsADLCandidate);
Candidate.IsADLCandidate = IsADLCandidate;
// Ignore the object argument if there is one, since we don't have an object
// type.
Candidate.IgnoreObjectArgument =
Expand Down Expand Up @@ -14122,8 +14125,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
/*IsExecConfig=*/false,
static_cast<CallExpr::ADLCallKind>((*Best)->IsADLCandidate));
/*IsExecConfig=*/false, (*Best)->IsADLCandidate);
}

case OR_No_Viable_Function: {
Expand Down Expand Up @@ -14182,8 +14184,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn,
return ExprError();
return SemaRef.BuildResolvedCallExpr(
Res.get(), FDecl, LParenLoc, Args, RParenLoc, ExecConfig,
/*IsExecConfig=*/false,
static_cast<CallExpr::ADLCallKind>((*Best)->IsADLCandidate));
/*IsExecConfig=*/false, (*Best)->IsADLCandidate);
}
}

Expand Down Expand Up @@ -14490,8 +14491,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Args[0] = Input;
CallExpr *TheCall = CXXOperatorCallExpr::Create(
Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc,
CurFPFeatureOverrides(),
static_cast<CallExpr::ADLCallKind>(Best->IsADLCandidate));
CurFPFeatureOverrides(), Best->IsADLCandidate);

if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl))
return ExprError();
Expand All @@ -14506,7 +14506,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
// operator node.
ExprResult InputRes = PerformImplicitConversion(
Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing,
CCK_ForBuiltinOverloadedOp);
CheckedConversionKind::ForBuiltinOverloadedOp);
if (InputRes.isInvalid())
return ExprError();
Input = InputRes.get();
Expand Down Expand Up @@ -14909,8 +14909,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// members; CodeGen should take care not to emit the this pointer.
TheCall = CXXOperatorCallExpr::Create(
Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc,
CurFPFeatureOverrides(),
static_cast<CallExpr::ADLCallKind>(Best->IsADLCandidate));
CurFPFeatureOverrides(), Best->IsADLCandidate);

if (const auto *Method = dyn_cast<CXXMethodDecl>(FnDecl);
Method && Method->isImplicitObjectMemberFunction()) {
Expand Down Expand Up @@ -14990,14 +14989,14 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
// operator node.
ExprResult ArgsRes0 = PerformImplicitConversion(
Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
AA_Passing, CCK_ForBuiltinOverloadedOp);
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();

ExprResult ArgsRes1 = PerformImplicitConversion(
Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
AA_Passing, CCK_ForBuiltinOverloadedOp);
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
Expand Down Expand Up @@ -15368,14 +15367,14 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc,
// operator node.
ExprResult ArgsRes0 = PerformImplicitConversion(
Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
AA_Passing, CCK_ForBuiltinOverloadedOp);
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes0.isInvalid())
return ExprError();
Args[0] = ArgsRes0.get();

ExprResult ArgsRes1 = PerformImplicitConversion(
Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
AA_Passing, CCK_ForBuiltinOverloadedOp);
AA_Passing, CheckedConversionKind::ForBuiltinOverloadedOp);
if (ArgsRes1.isInvalid())
return ExprError();
Args[1] = ArgsRes1.get();
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaPseudoObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT,
return;
QualType T = Getter->parameters()[0]->getType();
S.CheckObjCConversion(Key->getSourceRange(), T, Key,
Sema::CCK_ImplicitConversion);
CheckedConversionKind::Implicit);
}

bool ObjCSubscriptOpBuilder::findAtIndexGetter() {
Expand Down
14 changes: 1 addition & 13 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -12864,19 +12864,6 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
ArraySize = NewArraySize.get();
}

// Per C++0x [expr.new]p5, the type being constructed may be a
// typedef of an array type.
QualType AllocType = AllocTypeInfo->getType();
if (ArraySize) {
if (const ConstantArrayType *Array =
SemaRef.Context.getAsConstantArrayType(AllocType)) {
ArraySize = IntegerLiteral::Create(SemaRef.Context, Array->getSize(),
SemaRef.Context.getSizeType(),
E->getBeginLoc());
AllocType = Array->getElementType();
}
}

// Transform the placement arguments (if any).
bool ArgumentChanged = false;
SmallVector<Expr*, 8> PlacementArgs;
Expand Down Expand Up @@ -12938,6 +12925,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
return E;
}

QualType AllocType = AllocTypeInfo->getType();
if (!ArraySize) {
// If no array size was specified, but the new expression was
// instantiated with an array type (e.g., "new T" where T is
Expand Down
31 changes: 20 additions & 11 deletions clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,33 @@ class InvalidPtrChecker
bool InvalidatingGetEnv = false;

// GetEnv can be treated invalidating and non-invalidating as well.
const CallDescription GetEnvCall{{"getenv"}, 1};
const CallDescription GetEnvCall{CDM::CLibrary, {"getenv"}, 1};

const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
{{{"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{{"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{{"putenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{{"_putenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{{"_wputenv_s"}, 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{CDM::CLibrary, {"setenv"}, 3},
&InvalidPtrChecker::EnvpInvalidatingCall},
{{CDM::CLibrary, {"unsetenv"}, 1},
&InvalidPtrChecker::EnvpInvalidatingCall},
{{CDM::CLibrary, {"putenv"}, 1},
&InvalidPtrChecker::EnvpInvalidatingCall},
{{CDM::CLibrary, {"_putenv_s"}, 2},
&InvalidPtrChecker::EnvpInvalidatingCall},
{{CDM::CLibrary, {"_wputenv_s"}, 2},
&InvalidPtrChecker::EnvpInvalidatingCall},
};

void postPreviousReturnInvalidatingCall(const CallEvent &Call,
CheckerContext &C) const;

// SEI CERT ENV34-C
const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
{{{"setlocale"}, 2},
{{CDM::CLibrary, {"setlocale"}, 2},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
{{{"strerror"}, 1},
{{CDM::CLibrary, {"strerror"}, 1},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
{{{"localeconv"}, 0},
{{CDM::CLibrary, {"localeconv"}, 0},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
{{{"asctime"}, 1},
{{CDM::CLibrary, {"asctime"}, 1},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
};

Expand Down Expand Up @@ -205,8 +210,12 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
CE, LCtx, CE->getType(), C.blockCount());
State = State->BindExpr(CE, LCtx, RetVal);

const auto *SymRegOfRetVal =
dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
if (!SymRegOfRetVal)
return;

// Remember to this region.
const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.getAsRegion());
const MemRegion *MR = SymRegOfRetVal->getBaseRegion();
State = State->set<PreviousCallResultMap>(FD, MR);

Expand Down
10 changes: 10 additions & 0 deletions clang/test/Analysis/invalid-ptr-checker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,security.cert.env.InvalidPtr -verify %s

// expected-no-diagnostics

namespace other {
int strerror(int errnum); // custom strerror
void no_crash_on_custom_strerror() {
(void)strerror(0); // no-crash
}
} // namespace other
18 changes: 2 additions & 16 deletions clang/test/ClangScanDeps/error.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,10 @@
// RUN: rm -rf %t
// RUN: split-file %s %t

//--- missing_tu.json.in
[{
"directory": "DIR",
"command": "clang -fsyntax-only DIR/missing_tu.c",
"file": "DIR/missing_tu.c"
}]
//--- missing_header.json.in
[{
"directory": "DIR",
"command": "clang -fsyntax-only DIR/missing_header.c",
"file": "DIR/missing_header.c"
}]
//--- missing_header.c
#include "missing.h"

// RUN: sed -e "s|DIR|%/t|g" %t/missing_tu.json.in > %t/missing_tu.json
// RUN: not clang-scan-deps -compilation-database %t/missing_tu.json 2>%t/missing_tu.errs
// RUN: not clang-scan-deps -- %clang -c %t/missing_tu.c 2>%t/missing_tu.errs
// RUN: echo EOF >> %t/missing_tu.errs
// RUN: cat %t/missing_tu.errs | sed 's:\\\\\?:/:g' | FileCheck %s --check-prefix=CHECK-MISSING-TU -DPREFIX=%/t
// CHECK-MISSING-TU: Error while scanning dependencies for [[PREFIX]]/missing_tu.c
Expand All @@ -26,8 +13,7 @@
// CHECK-MISSING-TU-NEXT: error:
// CHECK-MISSING-TU-NEXT: EOF

// RUN: sed -e "s|DIR|%/t|g" %t/missing_header.json.in > %t/missing_header.json
// RUN: not clang-scan-deps -compilation-database %t/missing_header.json 2>%t/missing_header.errs
// RUN: not clang-scan-deps -- %clang -c %t/missing_header.c 2>%t/missing_header.errs
// RUN: echo EOF >> %t/missing_header.errs
// RUN: cat %t/missing_header.errs | sed 's:\\\\\?:/:g' | FileCheck %s --check-prefix=CHECK-MISSING-HEADER -DPREFIX=%/t
// CHECK-MISSING-HEADER: Error while scanning dependencies for [[PREFIX]]/missing_header.c
Expand Down
2 changes: 1 addition & 1 deletion clang/test/ClangScanDeps/module-format.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// RUN: rm -f %t/cdb_pch.json
// RUN: sed "s|DIR|%/t|g" %S/Inputs/modules-pch/cdb_pch.json > %t/cdb_pch.json
// RUN: clang-scan-deps -compilation-database %t/cdb_pch.json -format experimental-full \
// RUN: -module-files-dir %t/build > %t/result_pch.json
// RUN: -module-files-dir %t/build -o %t/result_pch.json

// Explicitly build the PCH:
//
Expand Down
29 changes: 29 additions & 0 deletions clang/test/CodeGen/builtin-allow-runtime-check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4
// RUN: %clang_cc1 -cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s

static_assert(__has_builtin(__builtin_allow_runtime_check), "");

// CHECK-LABEL: define dso_local noundef zeroext i1 @_Z4testv(
// CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.allow.runtime.check(metadata !"mycheck")
// CHECK-NEXT: ret i1 [[TMP0]]
//
bool test() {
return __builtin_allow_runtime_check("mycheck");
}

// CHECK-LABEL: define dso_local noundef zeroext i1 @_Z10test_twicev(
// CHECK-SAME: ) #[[ATTR0]] {
// CHECK-NEXT: entry:
// CHECK-NEXT: [[TMP0:%.*]] = call i1 @llvm.allow.runtime.check(metadata !"mycheck")
// CHECK-NEXT: [[CONV:%.*]] = zext i1 [[TMP0]] to i32
// CHECK-NEXT: [[TMP1:%.*]] = call i1 @llvm.allow.runtime.check(metadata !"mycheck")
// CHECK-NEXT: [[CONV1:%.*]] = zext i1 [[TMP1]] to i32
// CHECK-NEXT: [[OR:%.*]] = or i32 [[CONV]], [[CONV1]]
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[OR]], 0
// CHECK-NEXT: ret i1 [[TOBOOL]]
//
bool test_twice() {
return __builtin_allow_runtime_check("mycheck") | __builtin_allow_runtime_check("mycheck");
}
4 changes: 2 additions & 2 deletions clang/test/Driver/riscv-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
// RUN: %clang --target=riscv32-unknown-elf -### %s -mno-strict-align 2>&1 | FileCheck %s -check-prefix=FAST-UNALIGNED-ACCESS
// RUN: %clang --target=riscv32-unknown-elf -### %s -mstrict-align 2>&1 | FileCheck %s -check-prefix=NO-FAST-UNALIGNED-ACCESS

// FAST-UNALIGNED-ACCESS: "-target-feature" "+fast-unaligned-access"
// NO-FAST-UNALIGNED-ACCESS: "-target-feature" "-fast-unaligned-access"
// FAST-UNALIGNED-ACCESS: "-target-feature" "+unaligned-scalar-mem" "-target-feature" "+unaligned-vector-mem"
// NO-FAST-UNALIGNED-ACCESS: "-target-feature" "-unaligned-scalar-mem" "-target-feature" "-unaligned-vector-mem"

// RUN: %clang --target=riscv32-unknown-elf -### %s 2>&1 | FileCheck %s -check-prefix=NOUWTABLE
// RUN: %clang --target=riscv32-unknown-elf -fasynchronous-unwind-tables -### %s 2>&1 | FileCheck %s -check-prefix=UWTABLE
Expand Down
24 changes: 12 additions & 12 deletions clang/test/Headers/__clang_hip_math.hip
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@ extern "C" __device__ double test_j1(double x) {
// DEFAULT-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// DEFAULT-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// DEFAULT-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// DEFAULT-NEXT: [[DIV_I:%.*]] = fdiv contract float [[CONV_I]], [[Y]]
// DEFAULT-NEXT: [[MUL8_I:%.*]] = fmul contract float [[__X1_0_I3]], [[DIV_I]]
// DEFAULT-NEXT: [[SUB_I]] = fsub contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -1718,7 +1718,7 @@ extern "C" __device__ double test_j1(double x) {
// FINITEONLY-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// FINITEONLY-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// FINITEONLY-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// FINITEONLY-NEXT: [[DIV_I:%.*]] = fdiv nnan ninf contract float [[CONV_I]], [[Y]]
// FINITEONLY-NEXT: [[MUL8_I:%.*]] = fmul nnan ninf contract float [[__X1_0_I3]], [[DIV_I]]
// FINITEONLY-NEXT: [[SUB_I]] = fsub nnan ninf contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -1751,7 +1751,7 @@ extern "C" __device__ double test_j1(double x) {
// APPROX-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// APPROX-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// APPROX-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// APPROX-NEXT: [[DIV_I:%.*]] = fdiv contract float [[CONV_I]], [[Y]]
// APPROX-NEXT: [[MUL8_I:%.*]] = fmul contract float [[__X1_0_I3]], [[DIV_I]]
// APPROX-NEXT: [[SUB_I]] = fsub contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -1788,7 +1788,7 @@ extern "C" __device__ float test_jnf(int x, float y) {
// DEFAULT-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// DEFAULT-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// DEFAULT-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// DEFAULT-NEXT: [[DIV_I:%.*]] = fdiv contract double [[CONV_I]], [[Y]]
// DEFAULT-NEXT: [[MUL8_I:%.*]] = fmul contract double [[__X1_0_I3]], [[DIV_I]]
// DEFAULT-NEXT: [[SUB_I]] = fsub contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -1821,7 +1821,7 @@ extern "C" __device__ float test_jnf(int x, float y) {
// FINITEONLY-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// FINITEONLY-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// FINITEONLY-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// FINITEONLY-NEXT: [[DIV_I:%.*]] = fdiv nnan ninf contract double [[CONV_I]], [[Y]]
// FINITEONLY-NEXT: [[MUL8_I:%.*]] = fmul nnan ninf contract double [[__X1_0_I3]], [[DIV_I]]
// FINITEONLY-NEXT: [[SUB_I]] = fsub nnan ninf contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -1854,7 +1854,7 @@ extern "C" __device__ float test_jnf(int x, float y) {
// APPROX-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// APPROX-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// APPROX-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// APPROX-NEXT: [[DIV_I:%.*]] = fdiv contract double [[CONV_I]], [[Y]]
// APPROX-NEXT: [[MUL8_I:%.*]] = fmul contract double [[__X1_0_I3]], [[DIV_I]]
// APPROX-NEXT: [[SUB_I]] = fsub contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4222,7 +4222,7 @@ extern "C" __device__ double test_y1(double x) {
// DEFAULT-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// DEFAULT-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// DEFAULT-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// DEFAULT-NEXT: [[DIV_I:%.*]] = fdiv contract float [[CONV_I]], [[Y]]
// DEFAULT-NEXT: [[MUL8_I:%.*]] = fmul contract float [[__X1_0_I3]], [[DIV_I]]
// DEFAULT-NEXT: [[SUB_I]] = fsub contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4255,7 +4255,7 @@ extern "C" __device__ double test_y1(double x) {
// FINITEONLY-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// FINITEONLY-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// FINITEONLY-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// FINITEONLY-NEXT: [[DIV_I:%.*]] = fdiv nnan ninf contract float [[CONV_I]], [[Y]]
// FINITEONLY-NEXT: [[MUL8_I:%.*]] = fmul nnan ninf contract float [[__X1_0_I3]], [[DIV_I]]
// FINITEONLY-NEXT: [[SUB_I]] = fsub nnan ninf contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4288,7 +4288,7 @@ extern "C" __device__ double test_y1(double x) {
// APPROX-NEXT: [[__X1_0_I3:%.*]] = phi float [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[__X0_0_I2:%.*]] = phi float [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// APPROX-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to float
// APPROX-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to float
// APPROX-NEXT: [[DIV_I:%.*]] = fdiv contract float [[CONV_I]], [[Y]]
// APPROX-NEXT: [[MUL8_I:%.*]] = fmul contract float [[__X1_0_I3]], [[DIV_I]]
// APPROX-NEXT: [[SUB_I]] = fsub contract float [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4325,7 +4325,7 @@ extern "C" __device__ float test_ynf(int x, float y) {
// DEFAULT-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// DEFAULT-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// DEFAULT-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// DEFAULT-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// DEFAULT-NEXT: [[DIV_I:%.*]] = fdiv contract double [[CONV_I]], [[Y]]
// DEFAULT-NEXT: [[MUL8_I:%.*]] = fmul contract double [[__X1_0_I3]], [[DIV_I]]
// DEFAULT-NEXT: [[SUB_I]] = fsub contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4358,7 +4358,7 @@ extern "C" __device__ float test_ynf(int x, float y) {
// FINITEONLY-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// FINITEONLY-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// FINITEONLY-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// FINITEONLY-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// FINITEONLY-NEXT: [[DIV_I:%.*]] = fdiv nnan ninf contract double [[CONV_I]], [[Y]]
// FINITEONLY-NEXT: [[MUL8_I:%.*]] = fmul nnan ninf contract double [[__X1_0_I3]], [[DIV_I]]
// FINITEONLY-NEXT: [[SUB_I]] = fsub nnan ninf contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down Expand Up @@ -4391,7 +4391,7 @@ extern "C" __device__ float test_ynf(int x, float y) {
// APPROX-NEXT: [[__X1_0_I3:%.*]] = phi double [ [[SUB_I:%.*]], [[FOR_BODY_I]] ], [ [[CALL_I21_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[__X0_0_I2:%.*]] = phi double [ [[__X1_0_I3]], [[FOR_BODY_I]] ], [ [[CALL_I_I]], [[IF_END4_I]] ]
// APPROX-NEXT: [[MUL_I:%.*]] = shl nuw nsw i32 [[__I_0_I4]], 1
// APPROX-NEXT: [[CONV_I:%.*]] = sitofp i32 [[MUL_I]] to double
// APPROX-NEXT: [[CONV_I:%.*]] = uitofp nneg i32 [[MUL_I]] to double
// APPROX-NEXT: [[DIV_I:%.*]] = fdiv contract double [[CONV_I]], [[Y]]
// APPROX-NEXT: [[MUL8_I:%.*]] = fmul contract double [[__X1_0_I3]], [[DIV_I]]
// APPROX-NEXT: [[SUB_I]] = fsub contract double [[MUL8_I]], [[__X0_0_I2]]
Expand Down
7 changes: 7 additions & 0 deletions clang/test/Preprocessor/riscv-target-features.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
// CHECK-NOT: __riscv_za128rs {{.*$}}
// CHECK-NOT: __riscv_za64rs {{.*$}}
// CHECK-NOT: __riscv_zacas {{.*$}}
// CHECK-NOT: __riscv_zama16b {{.*$}}
// CHECK-NOT: __riscv_zawrs {{.*$}}
// CHECK-NOT: __riscv_zba {{.*$}}
// CHECK-NOT: __riscv_zbb {{.*$}}
Expand Down Expand Up @@ -704,6 +705,12 @@
// RUN: -o - | FileCheck --check-prefix=CHECK-ZACAS-EXT %s
// CHECK-ZACAS-EXT: __riscv_zacas 1000000{{$}}

// RUN: %clang --target=riscv32 -march=rv32izama16b -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZAMA16B-EXT %s
// RUN: %clang --target=riscv64 -march=rv64izama16b -x c -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZAMA16B-EXT %s
// CHECK-ZAMA16B-EXT: __riscv_zama16b 1000000{{$}}

// RUN: %clang --target=riscv32-unknown-linux-gnu \
// RUN: -march=rv32izawrs -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-ZAWRS-EXT %s
Expand Down
24 changes: 24 additions & 0 deletions clang/test/Sema/builtin-allow-runtime-check.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clang_cc1 -fsyntax-only -triple x86_64-pc-linux-gnu -verify %s
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s

extern const char *str;

int main(void) {
int r = 0;

r |= __builtin_allow_runtime_check(); // expected-error {{too few arguments to function call}}

r |= __builtin_allow_runtime_check(str); // expected-error {{expression is not a string literal}}

r |= __builtin_allow_runtime_check(5); // expected-error {{incompatible integer to pointer conversion}} expected-error {{expression is not a string literal}}

r |= __builtin_allow_runtime_check("a", "b"); // expected-error {{too many arguments to function call}}

r |= __builtin_allow_runtime_check("");

r |= __builtin_allow_runtime_check("check");

str = __builtin_allow_runtime_check("check2"); // expected-error {{incompatible integer to pointer conversion}}

return r;
}
23 changes: 0 additions & 23 deletions clang/test/SemaCXX/PR41441.cpp

This file was deleted.

Loading