104 changes: 69 additions & 35 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ def NonParmVar : SubsetSubject<Var,
def NonLocalVar : SubsetSubject<Var,
[{!S->hasLocalStorage()}],
"variables with non-local storage">;
def VarTmpl : SubsetSubject<Var, [{S->getDescribedVarTemplate()}],
"variable templates">;

def NonBitField : SubsetSubject<Field,
[{!S->isBitField()}],
"non-bit-field non-static data members">;
Expand Down Expand Up @@ -1916,7 +1919,7 @@ public:
}
auto getArgIdents() const { return ArgIdents; }
auto getArgLocs() const { return ArgLocs; }
void setParamIdx(size_t Idx, int Val) {
void setParamIdx(size_t Idx, int Val) {
assert(Idx < params_Size);
params_[Idx] = Val;
}
Expand Down Expand Up @@ -3260,33 +3263,28 @@ def Target : InheritableAttr {
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [TargetDocs];
let AdditionalMembers = [{
StringRef getArchitecture() const {
std::optional<StringRef> getX86Architecture() const {
StringRef Features = getFeaturesStr();
if (Features == "default") return {};

SmallVector<StringRef, 1> AttrFeatures;
Features.split(AttrFeatures, ",");

for (auto &Feature : AttrFeatures) {
SmallVector<StringRef, 4> AttrFeatures;
Features.split(AttrFeatures, ',');
for (StringRef Feature : AttrFeatures) {
Feature = Feature.trim();
if (Feature.starts_with("arch="))
return Feature.drop_front(sizeof("arch=") - 1);
}
return "";
return std::nullopt;
}

// Gets the list of features as simple string-refs with no +/- or 'no-'.
// Only adds the items to 'Out' that are additions.
void getAddedFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
void getX86AddedFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
if (isDefaultVersion())
return;
StringRef Features = getFeaturesStr();
if (Features == "default") return;

SmallVector<StringRef, 1> AttrFeatures;
Features.split(AttrFeatures, ",");

SmallVector<StringRef, 4> AttrFeatures;
Features.split(AttrFeatures, ',');
for (auto &Feature : AttrFeatures) {
Feature = Feature.trim();

if (!Feature.starts_with("no-") && !Feature.starts_with("arch=") &&
!Feature.starts_with("fpmath=") && !Feature.starts_with("tune="))
Out.push_back(Feature);
Expand All @@ -3297,24 +3295,24 @@ def Target : InheritableAttr {
}];
}

def TargetVersion : InheritableAttr {
def TargetVersion : InheritableAttr, TargetSpecificAttr<TargetArch<!listconcat(TargetAArch64.Arches, TargetRISCV.Arches)>> {
let Spellings = [GCC<"target_version">];
let Args = [StringArgument<"NamesStr">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [TargetVersionDocs];
let AdditionalMembers = [{
StringRef getName() const { return getNamesStr().trim(); }
bool isDefaultVersion() const {
return getName() == "default";
}
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out) const {
if (isDefaultVersion()) return;
StringRef Features = getName();

SmallVector<StringRef, 8> AttrFeatures;
Features.split(AttrFeatures, "+");
bool isDefaultVersion() const { return getName() == "default"; }

for (auto &Feature : AttrFeatures) {
void getFeatures(llvm::SmallVectorImpl<StringRef> &Out,
char Delim = '+') const {
if (isDefaultVersion())
return;
StringRef Features = getName();
SmallVector<StringRef, 4> AttrFeatures;
Features.split(AttrFeatures, Delim);
for (StringRef Feature : AttrFeatures) {
Feature = Feature.trim();
Out.push_back(Feature);
}
Expand All @@ -3331,20 +3329,40 @@ def TargetClones : InheritableAttr {
StringRef getFeatureStr(unsigned Index) const {
return *(featuresStrs_begin() + Index);
}

bool isDefaultVersion(unsigned Index) const {
return getFeatureStr(Index) == "default";
}

void getFeatures(llvm::SmallVectorImpl<StringRef> &Out,
unsigned Index) const {
if (isDefaultVersion(Index)) return;
unsigned Index, char Delim = '+') const {
if (isDefaultVersion(Index))
return;
StringRef Features = getFeatureStr(Index);
SmallVector<StringRef, 8> AttrFeatures;
Features.split(AttrFeatures, "+");
for (auto &Feature : AttrFeatures) {
SmallVector<StringRef, 4> AttrFeatures;
Features.split(AttrFeatures, Delim);
for (StringRef Feature : AttrFeatures) {
Feature = Feature.trim();
Out.push_back(Feature);
}
}

std::optional<StringRef> getX86Architecture(unsigned Index) const {
StringRef Feature = getFeatureStr(Index);
if (Feature.starts_with("arch="))
return Feature.drop_front(sizeof("arch=") - 1);
return std::nullopt;
}

void getX86Feature(llvm::SmallVectorImpl<StringRef> &Out,
unsigned Index) const {
if (isDefaultVersion(Index))
return;
if (getX86Architecture(Index))
return;
Out.push_back(getFeatureStr(Index));
}

// Given an index into the 'featuresStrs' sequence, compute a unique
// ID to be used with function name mangling for the associated variant.
// This mapping is necessary due to a requirement that the mangling ID
Expand Down Expand Up @@ -3428,6 +3446,15 @@ def DiagnoseIf : InheritableAttr {
let Documentation = [DiagnoseIfDocs];
}

def NoSpecializations : InheritableAttr {
let Spellings = [Clang<"no_specializations", /*AllowInC*/0>];
let Args = [StringArgument<"Message", 1>];
let Subjects = SubjectList<[ClassTmpl, FunctionTmpl, VarTmpl]>;
let Documentation = [NoSpecializationsDocs];
let MeaningfulToClassTemplateDefinition = 1;
let TemplateDependent = 1;
}

def ArcWeakrefUnavailable : InheritableAttr {
let Spellings = [Clang<"objc_arc_weak_reference_unavailable">];
let Subjects = SubjectList<[ObjCInterface], ErrorDiag>;
Expand Down Expand Up @@ -4621,6 +4648,13 @@ def HLSLNumThreads: InheritableAttr {
let Documentation = [NumThreadsDocs];
}

def HLSLSV_GroupID: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_GroupID">];
let Subjects = SubjectList<[ParmVar, Field]>;
let LangOpts = [HLSL];
let Documentation = [HLSLSV_GroupIDDocs];
}

def HLSLSV_GroupIndex: HLSLAnnotationAttr {
let Spellings = [HLSLAnnotation<"SV_GroupIndex">];
let Subjects = SubjectList<[ParmVar, GlobalVar]>;
Expand All @@ -4637,7 +4671,7 @@ def HLSLResourceBinding: InheritableAttr {
let AdditionalMembers = [{
public:
enum class RegisterType : unsigned { SRV, UAV, CBuffer, Sampler, C, I };

private:
RegisterType RegType;
unsigned SlotNumber;
Expand Down Expand Up @@ -4707,7 +4741,7 @@ def HLSLResource : InheritableAttr {
let Spellings = [];
let Subjects = SubjectList<[Struct]>;
let LangOpts = [HLSL];
let Args = [
let Args = [
EnumArgument<
"ResourceKind", "llvm::hlsl::ResourceKind",
/*is_string=*/0,
Expand All @@ -4732,7 +4766,7 @@ def HLSLResource : InheritableAttr {

def HLSLROV : TypeAttr {
let Spellings = [CXX11<"hlsl", "is_rov">];
let LangOpts = [HLSL];
let LangOpts = [HLSL];
let Documentation = [InternalOnly];
}

Expand All @@ -4757,7 +4791,7 @@ def HLSLContainedType : TypeAttr {

def HLSLRawBuffer : TypeAttr {
let Spellings = [CXX11<"hlsl", "raw_buffer">];
let LangOpts = [HLSL];
let LangOpts = [HLSL];
let Documentation = [InternalOnly];
}

Expand Down
53 changes: 37 additions & 16 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,15 @@ Query for this feature with ``__has_attribute(diagnose_if)``.
}];
}

def NoSpecializationsDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
``[[clang::no_specializations]]`` can be applied to function, class, or variable
templates which should not be explicitly specialized by users. This is primarily
used to diagnose user specializations of standard library type traits.
}];
}

def PassObjectSizeDocs : Documentation {
let Category = DocCatVariable; // Technically it's a parameter doc, but eh.
let Heading = "pass_object_size, pass_dynamic_object_size";
Expand Down Expand Up @@ -3943,7 +3952,7 @@ In this case, the capturing entity ``X`` could capture a dangling reference to t
temporary object.

.. code-block:: c++

void addToSet(std::string_view a [[clang::lifetime_capture_by(s)]], std::set<std::string_view>& s) {
s.insert(a);
}
Expand All @@ -3957,16 +3966,16 @@ temporary object.

The capturing entity ``X`` can be one of the following:

- Another (named) function parameter.
- Another (named) function parameter.

.. code-block:: c++

void addToSet(std::string_view a [[clang::lifetime_capture_by(s)]], std::set<std::string_view>& s) {
s.insert(a);
}

- ``this`` (in case of member functions).

.. code-block:: c++

class S {
Expand All @@ -3976,8 +3985,10 @@ The capturing entity ``X`` can be one of the following:
std::set<std::string_view> s;
};

Note: When applied to a constructor parameter, `[[clang::lifetime_capture_by(this)]]` is just an alias of `[[clang::lifetimebound]]`.

- `global`, `unknown`.

.. code-block:: c++

std::set<std::string_view> s;
Expand All @@ -4000,7 +4011,7 @@ function by writing the attribute after the function type:
The attribute supports specifying more than one capturing entities:

.. code-block:: c++

void addToSets(std::string_view a [[clang::lifetime_capture_by(s1, s2)]],
std::set<std::string_view>& s1,
std::set<std::string_view>& s2) {
Expand All @@ -4014,7 +4025,7 @@ statement-local and only detects use of a temporary as an argument to the
annotated parameter.

.. code-block:: c++

void addToSet(std::string_view a [[clang::lifetime_capture_by(s)]], std::set<std::string_view>& s);
void use() {
std::set<std::string_view> s;
Expand Down Expand Up @@ -7174,8 +7185,8 @@ the field it is attached to, and it may also lead to emission of automatic fix-i
hints which would help the user replace the use of unsafe functions(/fields) with safe
alternatives, though the attribute can be used even when the fix can't be automated.

* Attribute attached to functions: The attribute does not suppress
``-Wunsafe-buffer-usage`` inside the function to which it is attached.
* Attribute attached to functions: The attribute does not suppress
``-Wunsafe-buffer-usage`` inside the function to which it is attached.
These warnings still need to be addressed.

The attribute is warranted even if the only way a function can overflow
Expand Down Expand Up @@ -7238,10 +7249,10 @@ alternatives, though the attribute can be used even when the fix can't be automa
and then use the attribute on the original ``baz()`` to help the users
update their code to use the new function.

* Attribute attached to fields: The attribute should only be attached to
struct fields, if the fields can not be updated to a safe type with bounds
check, such as std::span. In other words, the buffers prone to unsafe accesses
should always be updated to use safe containers/views and attaching the attribute
* Attribute attached to fields: The attribute should only be attached to
struct fields, if the fields can not be updated to a safe type with bounds
check, such as std::span. In other words, the buffers prone to unsafe accesses
should always be updated to use safe containers/views and attaching the attribute
must be last resort when such an update is infeasible.

The attribute can be placed on individual fields or a set of them as shown below.
Expand All @@ -7259,7 +7270,7 @@ alternatives, though the attribute can be used even when the fix can't be automa
size_t sz;
};

Here, every read/write to the fields ptr1, ptr2, buf and sz will trigger a warning
Here, every read/write to the fields ptr1, ptr2, buf and sz will trigger a warning
that the field has been explcitly marked as unsafe due to unsafe-buffer operations.

}];
Expand Down Expand Up @@ -7814,10 +7825,10 @@ def HLSLLoopHintDocs : Documentation {
let Content = [{
The ``[loop]`` directive allows loop optimization hints to be
specified for the subsequent loop. The directive allows unrolling to
be disabled and is not compatible with [unroll(x)].
be disabled and is not compatible with [unroll(x)].

Specifying the parameter, ``[loop]``, directs the
unroller to not unroll the loop.
unroller to not unroll the loop.

.. code-block:: hlsl

Expand Down Expand Up @@ -7934,6 +7945,16 @@ randomized.
}];
}

def HLSLSV_GroupIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``SV_GroupID`` semantic, when applied to an input parameter, specifies which
thread group a shader is executing in. This attribute is only supported in compute shaders.

The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sv-groupid
}];
}

def HLSLSV_GroupIndexDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1354,7 +1354,7 @@ def ElementwiseLog10 : Builtin {

def ElementwisePopcount : Builtin {
let Spellings = ["__builtin_elementwise_popcount"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand Down Expand Up @@ -4882,7 +4882,6 @@ def HLSLSaturate : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}


def HLSLSelect : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_select"];
let Attributes = [NoThrow, Const];
Expand All @@ -4907,6 +4906,12 @@ def HLSLRadians : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLBufferUpdateCounter : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_buffer_update_counter"];
let Attributes = [NoThrow];
let Prototype = "uint32_t(...)";
}

def HLSLSplitDouble: LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_splitdouble"];
let Attributes = [NoThrow, Const];
Expand Down
67 changes: 66 additions & 1 deletion clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ TARGET_BUILTIN(__builtin_amdgcn_global_load_lds, "vv*1v*3IUiIiIUi", "t", "gfx940
TARGET_BUILTIN(__builtin_amdgcn_fdot2, "fV2hV2hfIb", "nc", "dot10-insts")
TARGET_BUILTIN(__builtin_amdgcn_fdot2_f16_f16, "hV2hV2hh", "nc", "dot9-insts")
TARGET_BUILTIN(__builtin_amdgcn_fdot2_bf16_bf16, "sV2sV2ss", "nc", "dot9-insts")
TARGET_BUILTIN(__builtin_amdgcn_fdot2_f32_bf16, "fV2sV2sfIb", "nc", "dot9-insts")
TARGET_BUILTIN(__builtin_amdgcn_fdot2_f32_bf16, "fV2sV2sfIb", "nc", "dot12-insts")
TARGET_BUILTIN(__builtin_amdgcn_sdot2, "SiV2SsV2SsSiIb", "nc", "dot2-insts")
TARGET_BUILTIN(__builtin_amdgcn_udot2, "UiV2UsV2UsUiIb", "nc", "dot2-insts")
TARGET_BUILTIN(__builtin_amdgcn_sdot4, "SiSiSiSiIb", "nc", "dot1-insts")
Expand All @@ -276,6 +276,7 @@ TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_bf8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_fp8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_fp8_fp8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_bf8, "fUiUif", "nc", "dot11-insts")
TARGET_BUILTIN(__builtin_amdgcn_fdot2c_f32_bf16, "fV2yV2yfIb", "nc", "dot13-insts")

//===----------------------------------------------------------------------===//
// GFX10+ only builtins.
Expand Down Expand Up @@ -462,6 +463,17 @@ TARGET_BUILTIN(__builtin_amdgcn_smfmac_f32_32x32x64_fp8_fp8, "V16fV4iV8iV16fiIiI
TARGET_BUILTIN(__builtin_amdgcn_permlane16_swap, "V2UiUiUiIbIb", "nc", "permlane16-swap")
TARGET_BUILTIN(__builtin_amdgcn_permlane32_swap, "V2UiUiUiIbIb", "nc", "permlane32-swap")

TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr4_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr6_b96_v3i32, "V3iV3i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr8_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4i16, "V4sV4s*3", "nc", "gfx950-insts")

TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_i8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_u8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")

TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_2xpk16_fp6_f32, "V6UiV16fV16ff", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_2xpk16_bf6_f32, "V6UiV16fV16ff", "nc", "gfx950-insts")

//===----------------------------------------------------------------------===//
// GFX12+ only builtins.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -554,6 +566,59 @@ TARGET_BUILTIN(__builtin_amdgcn_swmmac_f32_16x16x32_bf8_fp8_w64, "V4fiV2iV4fs",
TARGET_BUILTIN(__builtin_amdgcn_swmmac_f32_16x16x32_bf8_bf8_w64, "V4fiV2iV4fs", "nc", "gfx12-insts,wavefrontsize64")

TARGET_BUILTIN(__builtin_amdgcn_prng_b32, "UiUi", "nc", "prng-inst")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_fp6_f16, "V6UiV32hf", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_bf6_f16, "V6UiV32hf", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_fp6_bf16, "V6UiV32yf", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_bf6_bf16, "V6UiV32yf", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_f16_fp8, "V2hV2hifIiIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_f16_bf8, "V2hV2hifIiIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_f32_fp8, "fifIi", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_f32_bf8, "fifIi", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp8_f32, "V2sV2sfffIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf8_f32, "V2sV2sfffIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f32_fp8, "V2fUifIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f32_bf8, "V2fUifIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp8_f16, "V2sV2sV2hfIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp8_bf16, "V2sV2sV2yfIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf8_f16, "V2sV2sV2hfIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf8_bf16, "V2sV2sV2yfIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f32_fp4, "V2fUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp4_f32, "UiUifffIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f16_fp4, "V2hUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf16_fp4, "V2yUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_f32_fp6, "V32fV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_f32_bf6, "V32fV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_f16_fp6, "V32hV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_bf16_fp6, "V32yV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_f16_bf6, "V32hV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk32_bf16_bf6, "V32yV6Uif", "nc", "fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f16_fp8, "V2hUifIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf16_fp8, "V2yUifIb", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_f16_bf8, "V2hUifIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_bf16_bf8, "V2yUifIb", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp4_f16, "UiUiV2hfIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_pk_fp4_bf16, "UiUiV2yfIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f16, "UiUiV2hUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_bf16, "UiUiV2yUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk_fp4_f32, "UiUiV2fUifIi", "nc", "fp4-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_bf8_bf16, "iiyUifIi", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_bf8_f16, "iihUifIi", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_bf8_f32, "iifUifIi", "nc", "bf8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_fp8_bf16, "iiyUifIi", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_fp8_f16, "iihUifIi", "nc", "fp8-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_fp8_f32, "iifUifIi", "nc", "fp8-cvt-scale-insts")

TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_bf16, "V6UiV32yUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f16, "V6UiV32hUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f32, "V6UiV32fUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_bf16, "V6UiV32yUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f16, "V6UiV32hUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32, "V6UiV32fUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b32, "iiiiIUc", "nc", "bitop3-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUc", "nc", "bitop3-insts")

TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf16_f32, "V2yV2yfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_f16_f32, "V2hV2hfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")

#undef BUILTIN
#undef TARGET_BUILTIN
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -782,8 +782,8 @@ def err_module_odr_violation_field : Error<
"%select{"
"field %4|"
"field %4 with type %5|"
"%select{non-|}5bitfield %4|"
"bitfield %4 with one width expression|"
"%select{non-|}5bit-field %4|"
"bit-field %4 with one width expression|"
"%select{non-|}5mutable field %4|"
"field %4 with %select{no|an}5 initializer|"
"field %4 with an initializer"
Expand All @@ -793,8 +793,8 @@ def note_module_odr_violation_field : Note<
"%select{"
"field %3|"
"field %3 with type %4|"
"%select{non-|}4bitfield %3|"
"bitfield %3 with different width expression|"
"%select{non-|}4bit-field %3|"
"bit-field %3 with different width expression|"
"%select{non-|}4mutable field %3|"
"field %3 with %select{no|an}4 initializer|"
"field %3 with a different initializer"
Expand Down
8 changes: 5 additions & 3 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
def DeprecatedType : DiagGroup<"deprecated-type">;
def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedArrayCompare,
Expand All @@ -235,7 +236,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedType,
DeprecatedVolatile,
DeprecatedWritableStr,
DeprecatedRedundantConstexprStaticDef
DeprecatedRedundantConstexprStaticDef,
DeprecatedMissingCommaVariadicParam
]>,
DiagCategory<"Deprecations">;

Expand Down Expand Up @@ -683,7 +685,8 @@ def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">;
def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">;
def MemsetTransposedArgs : DiagGroup<"memset-transposed-args">;
def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">;
def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess">;
def NonTrivialMemcall : DiagGroup<"nontrivial-memcall">;
def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess", [NonTrivialMemcall]>;
def SuspiciousBzero : DiagGroup<"suspicious-bzero">;
def SuspiciousMemaccess : DiagGroup<"suspicious-memaccess",
[SizeofPointerMemaccess, DynamicClassMemaccess,
Expand Down Expand Up @@ -1589,4 +1592,3 @@ def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-stor

// A warning for options that enable a feature that is not yet complete
def ExperimentalOption : DiagGroup<"experimental-option">;

3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
"function scope depth exceeded maximum of %0">, DefaultFatal;
def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def warn_deprecated_missing_comma_before_ellipsis : Warning<
"declaration of a variadic function without a comma before '...' is deprecated">,
InGroup<DeprecatedMissingCommaVariadicParam>;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def warn_cxx98_compat_decltype : Warning<
Expand Down
31 changes: 21 additions & 10 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ def warn_cstruct_memaccess : Warning<
def warn_cxxstruct_memaccess : Warning<
"first argument in call to "
"%0 is a pointer to non-trivially copyable type %1">,
InGroup<NonTrivialMemaccess>;
InGroup<NonTrivialMemcall>;
def note_nontrivial_field : Note<
"field is non-trivial to %select{copy|default-initialize}0">;
def err_non_trivial_c_union_in_invalid_context : Error<
Expand Down Expand Up @@ -5445,6 +5445,10 @@ def note_dependent_function_template_spec_discard_reason : Note<
"candidate ignored: %select{not a function template|"
"not a member of the enclosing %select{class template|"
"namespace; did you mean to explicitly qualify the specialization?}1}0">;
def warn_invalid_specialization : Warning<
"%0 cannot be specialized%select{|: %2}1">,
DefaultError, InGroup<DiagGroup<"invalid-specialization">>;
def note_marked_here : Note<"marked %0 here">;

// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
Expand Down Expand Up @@ -6270,7 +6274,7 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">, InGroup<ZeroLengthArray>;
def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in %select{C++|SYCL device code}0">;
"zero-length arrays are not permitted in %select{C++|SYCL device code|HIP device code}0">;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
Expand Down Expand Up @@ -6417,7 +6421,7 @@ def warn_signed_bitfield_enum_conversion : Warning<
"enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def note_change_bitfield_sign : Note<
"consider making the bitfield type %select{unsigned|signed}0">;
"consider making the bit-field type %select{unsigned|signed}0">;

def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
Expand Down Expand Up @@ -6670,14 +6674,15 @@ def warn_counted_by_attr_elt_type_unknown_size :
// __builtin_counted_by_ref diagnostics:
def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
"'__builtin_counted_by_ref' argument must reference a flexible array member">;
def err_builtin_counted_by_ref_has_side_effects : Error<
"'__builtin_counted_by_ref' argument cannot have side-effects">;

def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"value returned by '__builtin_counted_by_ref' cannot be assigned to a "
"variable, have its address taken, or passed into or returned from a function">;
def err_builtin_counted_by_ref_invalid_lhs_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be %select{assigned to a "
"variable|passed into a function|returned from a function}0">;
def err_builtin_counted_by_ref_invalid_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be used in "
"%select{an array subscript|a binary}0 expression">;
def err_builtin_counted_by_ref_has_side_effects : Error<
"'__builtin_counted_by_ref' argument cannot have side-effects">;

let CategoryName = "ARC Semantic Issue" in {

Expand Down Expand Up @@ -7287,6 +7292,8 @@ def err_typecheck_illegal_increment_decrement : Error<
"cannot %select{decrement|increment}1 value of type %0">;
def err_typecheck_expect_int : Error<
"used type %0 where integer is required">;
def err_typecheck_expect_hlsl_resource : Error<
"used type %0 where __hlsl_resource_t is required">;
def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
"arithmetic on a pointer to %select{an incomplete|sizeless}0 type %1">;
def err_typecheck_pointer_arith_function_type : Error<
Expand Down Expand Up @@ -11396,7 +11403,7 @@ def err_omp_atomic_weak_no_equality : Error<"expected '==' operator for 'weak' c
def err_omp_atomic_several_clauses : Error<
"directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update', 'capture', or 'compare' clause">;
def err_omp_several_mem_order_clauses : Error<
"directive '#pragma omp %0' cannot contain more than one %select{'seq_cst', 'relaxed', |}1'acq_rel', 'acquire' or 'release' clause">;
"directive '#pragma omp %0' cannot contain more than one 'seq_cst',%select{ 'relaxed',|}1 'acq_rel', 'acquire' or 'release' clause">;
def err_omp_atomic_incompatible_mem_order_clause : Error<
"directive '#pragma omp atomic%select{ %0|}1' cannot be used with '%2' clause">;
def note_omp_previous_mem_order_clause : Note<
Expand Down Expand Up @@ -12528,6 +12535,10 @@ def warn_attr_min_eq_max: Warning<

def err_hlsl_attribute_number_arguments_insufficient_shader_model: Error<
"attribute %0 with %1 arguments requires shader model %2 or greater">;
def err_hlsl_expect_arg_const_int_one_or_neg_one: Error<
"argument %0 must be constant integer 1 or -1">;
def err_invalid_hlsl_resource_type: Error<
"invalid __hlsl_resource_t type attributes">;

// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
Expand Down Expand Up @@ -12781,5 +12792,5 @@ def err_acc_loop_not_monotonic

// AMDGCN builtins diagnostics
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">;
} // end of sema component.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ namespace clang {
bool isTupleSet() const { return Flags & IsTupleSet; }
bool isReadZA() const { return Flags & IsReadZA; }
bool isWriteZA() const { return Flags & IsWriteZA; }
bool setsFPMR() const { return Flags & SetsFPMR; }
bool isReductionQV() const { return Flags & IsReductionQV; }
uint64_t getBits() const { return Flags; }
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
Expand Down
6 changes: 1 addition & 5 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1525,14 +1525,10 @@ class TargetInfo : public TransferrableTargetInfo,

// Return the target-specific priority for features/cpus/vendors so
// that they can be properly sorted for checking.
virtual unsigned multiVersionSortPriority(StringRef Name) const {
virtual unsigned getFMVPriority(ArrayRef<StringRef> Features) const {
return 0;
}

// Return the target-specific cost for feature
// that taken into account in priority sorting.
virtual unsigned multiVersionFeatureCost() const { return 0; }

// Validate the contents of the __builtin_cpu_is(const char*)
// argument.
virtual bool validateCpuIs(StringRef Name) const { return false; }
Expand Down
40 changes: 21 additions & 19 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone,
////////////////////////////////////////////////////////////////////////////////
// While comparisons

def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;

////////////////////////////////////////////////////////////////////////////////
// Counting bit
Expand Down Expand Up @@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNon
def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down Expand Up @@ -2286,7 +2286,7 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in {
def SVTBLQ : SInst<"svtblq[_{d}]", "ddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tblq">;
def SVTBXQ : SInst<"svtbxq[_{d}]", "dddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tbxq">;
// EXTQ
def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheck0_15>]>;
def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheckLaneIndex, 0>]>;

// PMOV
// Move to Pred
Expand Down Expand Up @@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in {
// Multi-vector convert to/from floating-point.
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;

def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
Expand All @@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in {
// Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
}

Expand Down Expand Up @@ -2422,14 +2422,16 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>;
}

//
// Multi-vector scaling
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
// Multi-vector scaling
def FSCALE_SINGLE_X2 : Inst<"svscale[_single_{d}_x2]", "22x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x2", [IsStreaming],[]>;
def FSCALE_SINGLE_X4 : Inst<"svscale[_single_{d}_x4]", "44x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x4", [IsStreaming],[]>;
def FSCALE_X2 : Inst<"svscale[_{d}_x2]", "222.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x2", [IsStreaming],[]>;
def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x4", [IsStreaming],[]>;

// Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector
def SVF1CVTL : Inst<"svcvtl1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming, SetsFPMR], []>;
def SVF2CVTL : Inst<"svcvtl2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming, SetsFPMR], []>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/arm_sve_sme_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ include "arm_immcheck_incl.td"
// l: int64_t
// m: uint32_t
// n: uint64_t
// >: fpm_t

// [: svuint8_t
// t: svint32_t
Expand All @@ -103,6 +104,7 @@ include "arm_immcheck_incl.td"
// M: svfloat32_t
// N: svfloat64_t
// $: svbfloat16_t
// ~: svmfloat8_t

// J: Prefetch type (sv_prfop)

Expand Down Expand Up @@ -235,6 +237,7 @@ def IsInOutZA : FlagType<0x200000000000>;
def IsInZT0 : FlagType<0x400000000000>;
def IsOutZT0 : FlagType<0x800000000000>;
def IsInOutZT0 : FlagType<0x1000000000000>;
def SetsFPMR : FlagType<0x2000000000000>;

defvar InvalidMode = "";

Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,7 @@ def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Grou
Visibility<[ClangOption, CLOption]>;
def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CLOption, CC1Option]>,
HelpText<"Enable sample-based profile guided optimizations">,
MarshallingInfoString<CodeGenOpts<"SampleProfileFile">>;
def fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">,
Expand Down Expand Up @@ -5413,10 +5413,18 @@ def mlam_bh : Flag<["-"], "mlam-bh">, Group<m_loongarch_Features_Group>,
HelpText<"Enable amswap[_db].{b/h} and amadd[_db].{b/h}">;
def mno_lam_bh : Flag<["-"], "mno-lam-bh">, Group<m_loongarch_Features_Group>,
HelpText<"Disable amswap[_db].{b/h} and amadd[_db].{b/h}">;
def mlamcas : Flag<["-"], "mlamcas">, Group<m_loongarch_Features_Group>,
HelpText<"Enable amcas[_db].{b/h/w/d}">;
def mno_lamcas : Flag<["-"], "mno-lamcas">, Group<m_loongarch_Features_Group>,
HelpText<"Disable amcas[_db].{b/h/w/d}">;
def mld_seq_sa : Flag<["-"], "mld-seq-sa">, Group<m_loongarch_Features_Group>,
HelpText<"Do not generate load-load barrier instructions (dbar 0x700)">;
def mno_ld_seq_sa : Flag<["-"], "mno-ld-seq-sa">, Group<m_loongarch_Features_Group>,
HelpText<"Generate load-load barrier instructions (dbar 0x700)">;
def mdiv32 : Flag<["-"], "mdiv32">, Group<m_loongarch_Features_Group>,
HelpText<"Use div.w[u] and mod.w[u] instructions with input not sign-extended.">;
def mno_div32 : Flag<["-"], "mno-div32">, Group<m_loongarch_Features_Group>,
HelpText<"Do not use div.w[u] and mod.w[u] instructions with input not sign-extended.">;
def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
Expand Down
48 changes: 23 additions & 25 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2506,9 +2506,9 @@ struct FormatStyle {
/// lists.
///
/// Important differences:
/// - No spaces inside the braced list.
/// - No line break before the closing brace.
/// - Indentation with the continuation indent, not with the block indent.
/// * No spaces inside the braced list.
/// * No line break before the closing brace.
/// * Indentation with the continuation indent, not with the block indent.
///
/// Fundamentally, C++11 braced lists are formatted exactly like function
/// calls would be formatted in their place. If the braced list follows a name
Expand Down Expand Up @@ -3742,19 +3742,19 @@ struct FormatStyle {
QualifierAlignmentStyle QualifierAlignment;

/// The order in which the qualifiers appear.
/// Order is an array that can contain any of the following:
/// The order is an array that can contain any of the following:
///
/// * const
/// * inline
/// * static
/// * friend
/// * constexpr
/// * volatile
/// * restrict
/// * type
/// * ``const``
/// * ``inline``
/// * ``static``
/// * ``friend``
/// * ``constexpr``
/// * ``volatile``
/// * ``restrict``
/// * ``type``
///
/// \note
/// It **must** contain ``type``.
/// It must contain ``type``.
/// \endnote
///
/// Items to the left of ``type`` will be placed to the left of the type and
Expand Down Expand Up @@ -4970,12 +4970,11 @@ struct FormatStyle {
/// \version 12
std::vector<std::string> StatementAttributeLikeMacros;

/// A vector of macros that should be interpreted as complete
/// statements.
/// A vector of macros that should be interpreted as complete statements.
///
/// Typical macros are expressions, and require a semi-colon to be
/// added; sometimes this is not the case, and this allows to make
/// clang-format aware of such cases.
/// Typical macros are expressions and require a semicolon to be added.
/// Sometimes this is not the case, and this allows to make clang-format aware
/// of such cases.
///
/// For example: Q_UNUSED
/// \version 8
Expand Down Expand Up @@ -5450,10 +5449,10 @@ formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
/// cleaning up the code after that on success; otherwise, return an llvm::Error
/// carrying llvm::StringError.
/// This also supports inserting/deleting C++ #include directives:
/// - If a replacement has offset UINT_MAX, length 0, and a replacement text
/// * If a replacement has offset UINT_MAX, length 0, and a replacement text
/// that is an #include directive, this will insert the #include into the
/// correct block in the \p Code.
/// - If a replacement has offset UINT_MAX, length 1, and a replacement text
/// * If a replacement has offset UINT_MAX, length 1, and a replacement text
/// that is the name of the header to be removed, the header will be removed
/// from \p Code if it exists.
/// The include manipulation is done via ``tooling::HeaderInclude``, see its
Expand Down Expand Up @@ -5559,13 +5558,12 @@ extern const char *DefaultFallbackStyle;
///
/// ``StyleName`` can take several forms:
/// * "{<key>: <value>, ...}" - Set specic style parameters.
/// * "<style name>" - One of the style names supported by
/// getPredefinedStyle().
/// * "<style name>" - One of the style names supported by getPredefinedStyle().
/// * "file" - Load style configuration from a file called ``.clang-format``
/// located in one of the parent directories of ``FileName`` or the current
/// directory if ``FileName`` is empty.
/// located in one of the parent directories of ``FileName`` or the current
/// directory if ``FileName`` is empty.
/// * "file:<format_file_path>" to explicitly specify the configuration file to
/// use.
/// use.
///
/// \param[in] StyleName Style name to interpret according to the description
/// above.
Expand Down
13 changes: 12 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,17 @@ class Sema final : public SemaBase {

bool BuiltinNonDeterministicValue(CallExpr *TheCall);

enum BuiltinCountedByRefKind {
AssignmentKind,
InitializerKind,
FunctionArgKind,
ReturnArgKind,
ArraySubscriptKind,
BinaryExprKind,
};

bool CheckInvalidBuiltinCountedByRef(const Expr *E,
BuiltinCountedByRefKind K);
bool BuiltinCountedByRef(CallExpr *TheCall);

// Matrix builtin handling.
Expand Down Expand Up @@ -14257,7 +14268,7 @@ class Sema final : public SemaBase {
SourceLocation EllipsisLoc, Expr *IndexExpr,
SourceLocation RSquareLoc,
ArrayRef<Expr *> ExpandedExprs = {},
bool EmptyPack = false);
bool FullySubstituted = false);

/// Handle a C++1z fold-expression: ( expr op ... op expr ).
ExprResult ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS,
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class SemaHLSL : public SemaBase {
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
Expand All @@ -136,6 +137,9 @@ class SemaHLSL : public SemaBase {

bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);

// Diagnose whether the input ID is uint/unit2/uint3 type.
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL);

ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg);

QualType getInoutParameterType(QualType Ty);
Expand Down
23 changes: 10 additions & 13 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,6 @@ def ConversionChecker : Checker<"Conversion">,
HelpText<"Loss of sign/precision in implicit conversions">,
Documentation<HasDocumentation>;

def IdenticalExprChecker : Checker<"IdenticalExpr">,
HelpText<"Warn about unintended use of identical expressions in operators">,
Documentation<HasDocumentation>;

def FixedAddressChecker : Checker<"FixedAddr">,
HelpText<"Check for assignment of a fixed address to a pointer">,
Documentation<HasDocumentation>;
Expand Down Expand Up @@ -457,6 +453,12 @@ def CStringModeling : Checker<"CStringModeling">,
Documentation<NotDocumented>,
Hidden;

def CStringNotNullTerm : Checker<"NotNullTerminated">,
HelpText<"Check for arguments passed to C string functions which are not "
"null-terminated strings">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringNullArg : Checker<"NullArg">,
HelpText<"Check for null pointers being passed as arguments to C string "
"functions">,
Expand All @@ -483,11 +485,6 @@ def CStringBufferOverlap : Checker<"BufferOverlap">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringNotNullTerm : Checker<"NotNullTerminated">,
HelpText<"Check for arguments which are not null-terminating strings">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringUninitializedRead : Checker<"UninitializedRead">,
HelpText<"Checks if the string manipulation function would read uninitialized bytes">,
Dependencies<[CStringModeling]>,
Expand Down Expand Up @@ -598,14 +595,14 @@ def VforkChecker : Checker<"Vfork">,
HelpText<"Check for proper usage of vfork">,
Documentation<HasDocumentation>;

} // end "unix"

let ParentPackage = UnixAlpha in {

def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
Documentation<HasDocumentation>;

} // end "unix"

let ParentPackage = UnixAlpha in {

def PthreadLockChecker : Checker<"PthreadLock">,
HelpText<"Simple lock -> unlock checker">,
Dependencies<[PthreadLockBase]>,
Expand Down
32 changes: 6 additions & 26 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,47 +429,27 @@ class BranchNodeBuilder: public NodeBuilder {
const CFGBlock *DstT;
const CFGBlock *DstF;

bool InFeasibleTrue;
bool InFeasibleFalse;

void anchor() override;

public:
BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcNode, DstSet, C), DstT(DT), DstF(DF) {
// The branch node builder does not generate autotransitions.
// If there are no successors it means that both branches are infeasible.
takeNodes(SrcNode);
}

BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcSet, DstSet, C), DstT(DT), DstF(DF) {
takeNodes(SrcSet);
}

ExplodedNode *generateNode(ProgramStateRef State, bool branch,
ExplodedNode *Pred);

const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}

void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = true;
else
InFeasibleFalse = true;
}

bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
};

class IndirectGotoNodeBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ class ProgramState : public llvm::FoldingSetNode {
friend void ProgramStateRetain(const ProgramState *state);
friend void ProgramStateRelease(const ProgramState *state);

SVal desugarReference(SVal Val) const;
SVal wrapSymbolicRegion(SVal Base) const;
};

Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Tooling/Inclusions/IncludeStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ struct IncludeStyle {
/// When guessing whether a #include is the "main" include (to assign
/// category 0, see above), use this regex of allowed suffixes to the header
/// stem. A partial match is done, so that:
/// - "" means "arbitrary suffix"
/// - "$" means "no suffix"
/// * ``""`` means "arbitrary suffix"
/// * ``"$"`` means "no suffix"
///
/// For example, if configured to "(_test)?$", then a header a.h would be seen
/// For example, if configured to ``"(_test)?$"``, then a header a.h would be seen
/// as the "main" include in both a.cc and a_test.cc.
/// \version 3.9
std::string IncludeIsMainRegex;
Expand Down
8 changes: 3 additions & 5 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6223,13 +6223,11 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
ArrayRef<QualType> Expansions,
int Index) const {
QualType Canonical;
bool ExpandsToEmptyPack = FullySubstituted && Expansions.empty();
if (FullySubstituted && Index != -1) {
Canonical = getCanonicalType(Expansions[Index]);
} else {
llvm::FoldingSetNodeID ID;
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr,
ExpandsToEmptyPack);
PackIndexingType::Profile(ID, *this, Pattern, IndexExpr, FullySubstituted);
void *InsertPos = nullptr;
PackIndexingType *Canon =
DependentPackIndexingTypes.FindNodeOrInsertPos(ID, InsertPos);
Expand All @@ -6238,7 +6236,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
Canon = new (Mem) PackIndexingType(*this, QualType(), Pattern, IndexExpr,
ExpandsToEmptyPack, Expansions);
FullySubstituted, Expansions);
DependentPackIndexingTypes.InsertNode(Canon, InsertPos);
}
Canonical = QualType(Canon, 0);
Expand All @@ -6248,7 +6246,7 @@ QualType ASTContext::getPackIndexingType(QualType Pattern, Expr *IndexExpr,
Allocate(PackIndexingType::totalSizeToAlloc<QualType>(Expansions.size()),
TypeAlignment);
auto *T = new (Mem) PackIndexingType(*this, Canonical, Pattern, IndexExpr,
ExpandsToEmptyPack, Expansions);
FullySubstituted, Expansions);
Types.push_back(T);
return QualType(T, 0);
}
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1899,11 +1899,17 @@ class TemplateDiff {

E = E->IgnoreImpCasts();

if (isa<IntegerLiteral>(E)) return false;
auto CheckIntegerLiteral = [](Expr *E) {
if (auto *TemplateExpr = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
E = TemplateExpr->getReplacement();
return isa<IntegerLiteral>(E);
};

if (CheckIntegerLiteral(E)) return false;

if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
if (UO->getOpcode() == UO_Minus)
if (isa<IntegerLiteral>(UO->getSubExpr()))
if (CheckIntegerLiteral(UO->getSubExpr()))
return false;

if (isa<CXXBoolLiteralExpr>(E))
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl::IDNS_TagFriend))
continue;

Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
if (FoundTemplate) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
Expand All @@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// see ASTTests test ImportExistingFriendClassTemplateDef.
continue;
}
// When importing a friend, it is possible that multiple declarations
// with same name can co-exist in specific cases (if a template contains
// a friend template and has a specialization). For this case the
// declarations should match, except that the "template depth" is
// different. No linking of previous declaration is needed in this case.
// FIXME: This condition may need refinement.
if (D->getFriendObjectKind() != Decl::FOK_None &&
FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
/*IgnoreTemplateParmDepth=*/true))
continue;

ConflictingDecls.push_back(FoundDecl);
}
}
Expand Down
102 changes: 73 additions & 29 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

QualType SubExprTy = SubExpr->getType();
std::optional<PrimType> FromT = classify(SubExprTy);
// Casts from integer/vector to vector.
if (CE->getType()->isVectorType())
return this->emitBuiltinBitCast(CE);

std::optional<PrimType> ToT = classify(CE->getType());
if (!FromT || !ToT)
return false;
Expand Down Expand Up @@ -1642,22 +1646,8 @@ bool Compiler<Emitter>::VisitImplicitValueInitExpr(
if (QT->isIncompleteArrayType())
return true;

if (QT->isArrayType()) {
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
assert(AT);
const auto *CAT = cast<ConstantArrayType>(AT);
size_t NumElems = CAT->getZExtSize();
PrimType ElemT = classifyPrim(CAT->getElementType());

for (size_t I = 0; I != NumElems; ++I) {
if (!this->visitZeroInitializer(ElemT, CAT->getElementType(), E))
return false;
if (!this->emitInitElem(ElemT, I, E))
return false;
}

return true;
}
if (QT->isArrayType())
return this->visitZeroArrayInitializer(QT, E);

if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
assert(Initializing);
Expand Down Expand Up @@ -3916,18 +3906,9 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
return false;
}
} else if (D->isCompositeArray()) {
const Record *ElemRecord = D->ElemDesc->ElemRecord;
assert(D->ElemDesc->ElemRecord);
for (uint32_t I = 0, N = D->getNumElems(); I != N; ++I) {
if (!this->emitConstUint32(I, E))
return false;
if (!this->emitArrayElemPtr(PT_Uint32, E))
return false;
if (!this->visitZeroRecordInitializer(ElemRecord, E))
return false;
if (!this->emitPopPtr(E))
return false;
}
// Can't be a vector or complex field.
if (!this->visitZeroArrayInitializer(D->getType(), E))
return false;
} else if (D->isRecord()) {
if (!this->visitZeroRecordInitializer(D->ElemRecord, E))
return false;
Expand Down Expand Up @@ -3958,6 +3939,52 @@ bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
return true;
}

template <class Emitter>
bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) {
assert(T->isArrayType() || T->isAnyComplexType() || T->isVectorType());
const ArrayType *AT = T->getAsArrayTypeUnsafe();
QualType ElemType = AT->getElementType();
size_t NumElems = cast<ConstantArrayType>(AT)->getZExtSize();

if (std::optional<PrimType> ElemT = classify(ElemType)) {
for (size_t I = 0; I != NumElems; ++I) {
if (!this->visitZeroInitializer(*ElemT, ElemType, E))
return false;
if (!this->emitInitElem(*ElemT, I, E))
return false;
}
return true;
} else if (ElemType->isRecordType()) {
const Record *R = getRecord(ElemType);

for (size_t I = 0; I != NumElems; ++I) {
if (!this->emitConstUint32(I, E))
return false;
if (!this->emitArrayElemPtr(PT_Uint32, E))
return false;
if (!this->visitZeroRecordInitializer(R, E))
return false;
if (!this->emitPopPtr(E))
return false;
}
return true;
} else if (ElemType->isArrayType()) {
for (size_t I = 0; I != NumElems; ++I) {
if (!this->emitConstUint32(I, E))
return false;
if (!this->emitArrayElemPtr(PT_Uint32, E))
return false;
if (!this->visitZeroArrayInitializer(ElemType, E))
return false;
if (!this->emitPopPtr(E))
return false;
}
return true;
}

return false;
}

template <class Emitter>
template <typename T>
bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
Expand Down Expand Up @@ -6471,8 +6498,25 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
}

// Get a pointer to the value-to-cast on the stack.
if (!this->visit(SubExpr))
// For CK_LValueToRValueBitCast, this is always an lvalue and
// we later assume it to be one (i.e. a PT_Ptr). However,
// we call this function for other utility methods where
// a bitcast might be useful, so convert it to a PT_Ptr in that case.
if (SubExpr->isGLValue() || FromType->isVectorType()) {
if (!this->visit(SubExpr))
return false;
} else if (std::optional<PrimType> FromT = classify(SubExpr)) {
unsigned TempOffset = allocateLocalPrimitive(
SubExpr, *FromT, /*IsConst=*/true, /*IsExtended=*/false);
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(*FromT, TempOffset, E))
return false;
if (!this->emitGetPtrLocal(TempOffset, E))
return false;
} else {
return false;
}

if (!ToT || ToT == PT_Ptr) {
if (!this->emitBitCastPtr(E))
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
bool visitZeroRecordInitializer(const Record *R, const Expr *E);
bool visitZeroArrayInitializer(QualType T, const Expr *E);

/// Emits an APSInt constant.
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
if (!Func)
return false;

APValue DummyResult;
if (!Run(Parent, Func, DummyResult))
if (!Run(Parent, Func))
return false;

return Func->isConstexpr();
Expand Down Expand Up @@ -213,13 +212,13 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
return Ctx.getFloatTypeSemantics(T);
}

bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
bool Context::Run(State &Parent, const Function *Func) {

{
InterpState State(Parent, *P, Stk, *this);
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
Func->getArgSize());
if (Interpret(State, Result)) {
if (Interpret(State)) {
assert(Stk.empty());
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Context final {

private:
/// Runs a function.
bool Run(State &Parent, const Function *Func, APValue &Result);
bool Run(State &Parent, const Function *Func);

/// Current compilation context.
ASTContext &Ctx;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APSInt toAPSInt(unsigned BitWidth) const {
return APSInt(toAPInt(BitWidth), !Signed);
}
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APInt(Bits, static_cast<uint64_t>(V), Signed)
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
using namespace clang;
using namespace clang::interp;

static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
static bool RetValue(InterpState &S, CodePtr &Pt) {
llvm::report_fatal_error("Interpreter cannot return values");
}

Expand Down Expand Up @@ -1205,11 +1205,10 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
if (Interpret(S)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
Expand Down Expand Up @@ -1270,11 +1269,10 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
S.Current = NewFrame.get();

InterpStateCCOverride CCOverride(S, Func->getDecl()->isImmediateFunction());
APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
if (Interpret(S)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
Expand Down Expand Up @@ -1598,7 +1596,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
#endif
bool Interpret(InterpState &S, APValue &Result) {
bool Interpret(InterpState &S) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
// to return from this function and thus terminate
Expand Down
17 changes: 5 additions & 12 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ namespace interp {
using APSInt = llvm::APSInt;
using FixedPointSemantics = llvm::FixedPointSemantics;

/// Convert a value to an APValue.
template <typename T>
bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
R = V.toAPValue(S.getASTContext());
return true;
}

/// Checks if the variable has externally defined storage.
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

Expand Down Expand Up @@ -299,7 +292,7 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);

/// Interpreter entry point.
bool Interpret(InterpState &S, APValue &Result);
bool Interpret(InterpState &S);

/// Interpret a builtin function.
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
Expand All @@ -321,7 +314,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
const Function *Func);

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
bool Ret(InterpState &S, CodePtr &PC) {
const T &Ret = S.Stk.pop<T>();

// Make sure returned pointers are live. We might be trying to return a
Expand Down Expand Up @@ -349,13 +342,13 @@ bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
} else {
delete S.Current;
S.Current = nullptr;
if (!ReturnValue<T>(S, Ret, Result))
return false;
// The topmost frame should come from an EvalEmitter,
// which has its own implementation of the Ret<> instruction.
}
return true;
}

inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
inline bool RetVoid(InterpState &S, CodePtr &PC) {
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");

if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
Expand Down
151 changes: 144 additions & 7 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,23 @@ static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) {
std::optional<PrimType> T = S.getContext().classify(QT);
assert(T);

unsigned BitWidth = S.getASTContext().getTypeSize(QT);
if (QT->isSignedIntegerOrEnumerationType()) {
int64_t V = Val.getSExtValue();
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
} else {
assert(QT->isUnsignedIntegerOrEnumerationType());
uint64_t V = Val.getZExtValue();
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
}
}

template <typename T>
static void pushInteger(InterpState &S, T Val, QualType QT) {
if constexpr (std::is_same_v<T, APInt>)
pushInteger(S, APSInt(Val, !std::is_signed_v<T>), QT);
else if constexpr (std::is_same_v<T, APSInt>)
pushInteger(S, Val, QT);
else
pushInteger(S,
APSInt(APInt(sizeof(T) * 8, static_cast<uint64_t>(Val),
Expand All @@ -116,14 +119,14 @@ static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) {
ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); });
}

static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
static bool retPrimValue(InterpState &S, CodePtr OpPC,
std::optional<PrimType> &T) {
if (!T)
return RetVoid(S, OpPC, Result);
return RetVoid(S, OpPC);

#define RET_CASE(X) \
case X: \
return Ret<X>(S, OpPC, Result);
return Ret<X>(S, OpPC);
switch (*T) {
RET_CASE(PT_Ptr);
RET_CASE(PT_FnPtr);
Expand All @@ -137,6 +140,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
RET_CASE(PT_Uint32);
RET_CASE(PT_Sint64);
RET_CASE(PT_Uint64);
RET_CASE(PT_IntAP);
RET_CASE(PT_IntAPS);
default:
llvm_unreachable("Unsupported return type for builtin function");
}
Expand Down Expand Up @@ -1684,10 +1689,123 @@ static bool interp__builtin_arithmetic_fence(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());

unsigned ID = Func->getBuiltinID();
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH_NO_BOOL(ElemT, {
T Result = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
T PrevResult = Result;

if (ID == Builtin::BI__builtin_reduce_add) {
if (T::add(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth + 1;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) +
Elem.toAPSInt(OverflowBits)));
return false;
}
} else if (ID == Builtin::BI__builtin_reduce_mul) {
if (T::mul(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth * 2;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) *
Elem.toAPSInt(OverflowBits)));
return false;
}

} else if (ID == Builtin::BI__builtin_reduce_and) {
(void)T::bitAnd(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_or) {
(void)T::bitOr(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_xor) {
(void)T::bitXor(Result, Elem, BitWidth, &Result);
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
}
pushInteger(S, Result.toAPSInt(), Call->getType());
});

return true;
}

/// Can be called with an integer or vector as the first and only parameter.
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
assert(Call->getNumArgs() == 1);
if (Call->getArg(0)->getType()->isIntegerType()) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
// Otherwise, the argument must be a vector.
assert(Call->getArg(0)->getType()->isVectorType());
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());
const Pointer &Dst = S.Stk.peek<Pointer>(primSize(PT_Ptr) * 2);
assert(Dst.getFieldDesc()->isPrimitiveArray());
assert(Arg.getFieldDesc()->getNumElems() ==
Dst.getFieldDesc()->getNumElems());

QualType ElemType = Arg.getFieldDesc()->getElemQualType();
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

// FIXME: Reading from uninitialized vector elements?
for (unsigned I = 0; I != NumElems; ++I) {
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
Dst.atIndex(I).deref<T>() =
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
});
}

return true;
}
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
assert(Call->getNumArgs() == 3);
Pointer DestPtr = getParam<Pointer>(Frame, 0);
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");

if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

// If the size is zero, we treat this as always being a valid no-op.
if (Size.isZero()) {
S.Stk.push<Pointer>(DestPtr);
return true;
}

if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr))
return false;

S.Stk.push<Pointer>(DestPtr);
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call, uint32_t BuiltinID) {
const InterpFrame *Frame = S.Current;
APValue Dummy;

std::optional<PrimType> ReturnT = S.getContext().classify(Call);

Expand Down Expand Up @@ -2130,6 +2248,25 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_reduce_add:
case Builtin::BI__builtin_reduce_mul:
case Builtin::BI__builtin_reduce_and:
case Builtin::BI__builtin_reduce_or:
case Builtin::BI__builtin_reduce_xor:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_elementwise_popcount:
if (!interp__builtin_elementwise_popcount(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_memcpy:
if (!interp__builtin_memcpy(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand All @@ -2138,7 +2275,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
}

return retPrimValue(S, OpPC, Dummy, ReturnT);
return retPrimValue(S, OpPC, ReturnT);
}

bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/AST/ByteCode/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,12 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const {
if (Func && !funcHasUsableBody(Func) && Caller)
return Caller->getSource(RetPC);

return S.getSource(Func, PC);
// Similarly, if the resulting source location is invalid anyway,
// point to the caller instead.
SourceInfo Result = S.getSource(Func, PC);
if (Result.getLoc().isInvalid() && Caller)
return Caller->getSource(RetPC);
return Result;
}

const Expr *InterpFrame::getExpr(CodePtr PC) const {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/AST/ComputeDependence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,8 @@ ExprDependence clang::computeDependence(PackIndexingExpr *E) {
ExprDependence::Instantiation;

ArrayRef<Expr *> Exprs = E->getExpressions();
if (Exprs.empty())
if (Exprs.empty() || !E->isFullySubstituted())
D |= PatternDep | ExprDependence::Instantiation;

else if (!E->getIndexExpr()->isInstantiationDependent()) {
std::optional<unsigned> Index = E->getSelectedIndex();
assert(Index && *Index < Exprs.size() && "pack index out of bound");
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
data().NeedOverloadResolutionForDestructor = true;
}

// C++2a [dcl.constexpr]p4:
// The definition of a constexpr destructor [shall] satisfy the
// following requirement:
// C++20 [dcl.constexpr]p5:
// The definition of a constexpr destructor whose function-body is not
// = delete shall additionally satisfy the following requirement:
// -- for every subobject of class type or (possibly multi-dimensional)
// array thereof, that class type shall have a constexpr destructor
if (!Subobj->hasConstexprDestructor())
Expand Down Expand Up @@ -1213,8 +1213,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DefaultedCopyAssignmentIsDeleted = true;
if (FieldRec->hasNonTrivialMoveAssignment())
data().DefaultedMoveAssignmentIsDeleted = true;
if (FieldRec->hasNonTrivialDestructor())
if (FieldRec->hasNonTrivialDestructor()) {
data().DefaultedDestructorIsDeleted = true;
// C++20 [dcl.constexpr]p5:
// The definition of a constexpr destructor whose function-body is
// not = delete shall additionally satisfy...
data().DefaultedDestructorIsConstexpr = true;
}
}

// For an anonymous union member, our overload resolution will perform
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/AST/ExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1717,9 +1717,9 @@ NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
PackIndexingExpr *PackIndexingExpr::Create(
ASTContext &Context, SourceLocation EllipsisLoc, SourceLocation RSquareLoc,
Expr *PackIdExpr, Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs, bool ExpandedToEmptyPack) {
ArrayRef<Expr *> SubstitutedExprs, bool FullySubstituted) {
QualType Type;
if (Index && !SubstitutedExprs.empty())
if (Index && FullySubstituted && !SubstitutedExprs.empty())
Type = SubstitutedExprs[*Index]->getType();
else
Type = Context.DependentTy;
Expand All @@ -1728,7 +1728,7 @@ PackIndexingExpr *PackIndexingExpr::Create(
Context.Allocate(totalSizeToAlloc<Expr *>(SubstitutedExprs.size()));
return new (Storage)
PackIndexingExpr(Type, EllipsisLoc, RSquareLoc, PackIdExpr, IndexExpr,
SubstitutedExprs, ExpandedToEmptyPack);
SubstitutedExprs, FullySubstituted);
}

NamedDecl *PackIndexingExpr::getPackDecl() const {
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11005,6 +11005,7 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitCallExpr(const CallExpr *E);
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);

Expand Down Expand Up @@ -11302,6 +11303,35 @@ static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
return false;
}

bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
return ExprEvaluatorBaseTy::VisitCallExpr(E);

switch (E->getBuiltinCallee()) {
default:
return false;
case Builtin::BI__builtin_elementwise_popcount: {
APValue Source;
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
return false;

QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
unsigned SourceLen = Source.getVectorLength();
SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen);

for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APSInt Elt = Source.getVectorElt(EltNum).getInt();
ResultElements.push_back(
APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
}
}

bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
APValue Source;
QualType SourceVecType = E->getSrcExpr()->getType();
Expand Down Expand Up @@ -13118,6 +13148,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
case Builtin::BI__builtin_popcountg:
case Builtin::BI__builtin_elementwise_popcount:
case Builtin::BI__popcnt16: // Microsoft variants of popcount
case Builtin::BI__popcnt:
case Builtin::BI__popcnt64: {
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ class CXXNameMangler {
static StringRef getCallingConvQualifierName(CallingConv CC);
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
void mangleExtFunctionInfo(const FunctionType *T);
void mangleSMEAttrs(unsigned SMEAttrs);
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
Expand Down Expand Up @@ -3532,6 +3533,69 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
// FIXME: noreturn
}

enum class AAPCSBitmaskSME : unsigned {
ArmStreamingBit = 1 << 0,
ArmStreamingCompatibleBit = 1 << 1,
ArmAgnosticSMEZAStateBit = 1 << 2,
ZA_Shift = 3,
ZT0_Shift = 6,
NoState = 0b000,
ArmIn = 0b001,
ArmOut = 0b010,
ArmInOut = 0b011,
ArmPreserves = 0b100,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ArmPreserves << ZT0_Shift)
};

static AAPCSBitmaskSME encodeAAPCSZAState(unsigned SMEAttrs) {
switch (SMEAttrs) {
case FunctionType::ARM_None:
return AAPCSBitmaskSME::NoState;
case FunctionType::ARM_In:
return AAPCSBitmaskSME::ArmIn;
case FunctionType::ARM_Out:
return AAPCSBitmaskSME::ArmOut;
case FunctionType::ARM_InOut:
return AAPCSBitmaskSME::ArmInOut;
case FunctionType::ARM_Preserves:
return AAPCSBitmaskSME::ArmPreserves;
default:
llvm_unreachable("Unrecognised SME attribute");
}
}

// The mangling scheme for function types which have SME attributes is
// implemented as a "pseudo" template:
//
// '__SME_ATTRS<<normal_function_type>, <sme_state>>'
//
// Combining the function type with a bitmask representing the streaming and ZA
// properties of the function's interface.
//
// Mangling of SME keywords is described in more detail in the AArch64 ACLE:
// https://github.com/ARM-software/acle/blob/main/main/acle.md#c-mangling-of-sme-keywords
//
void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
if (!SMEAttrs)
return;

AAPCSBitmaskSME Bitmask = AAPCSBitmaskSME(0);
if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingBit;
else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingCompatibleBit;

// TODO: Must represent __arm_agnostic("sme_za_state")

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZAState(SMEAttrs))
<< AAPCSBitmaskSME::ZA_Shift;

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZT0State(SMEAttrs))
<< AAPCSBitmaskSME::ZT0_Shift;

Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE";
}

void
CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// Vendor-specific qualifiers are emitted in reverse alphabetical order.
Expand Down Expand Up @@ -3569,6 +3633,11 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
unsigned SMEAttrs = T->getAArch64SMEAttributes();

if (SMEAttrs)
Out << "11__SME_ATTRSI";

mangleExtFunctionInfo(T);

// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
Expand Down Expand Up @@ -3603,6 +3672,8 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
mangleRefQualifier(T->getRefQualifier());

Out << 'E';

mangleSMEAttrs(SMEAttrs);
}

void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2514,7 +2514,10 @@ void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
}

void StmtPrinter::VisitPackIndexingExpr(PackIndexingExpr *E) {
OS << E->getPackIdExpression() << "...[" << E->getIndexExpr() << "]";
PrintExpr(E->getPackIdExpression());
OS << "...[";
PrintExpr(E->getIndexExpr());
OS << "]";
}

void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
Expand Down
8 changes: 4 additions & 4 deletions clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4031,12 +4031,12 @@ void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,

PackIndexingType::PackIndexingType(const ASTContext &Context,
QualType Canonical, QualType Pattern,
Expr *IndexExpr, bool ExpandsToEmptyPack,
Expr *IndexExpr, bool FullySubstituted,
ArrayRef<QualType> Expansions)
: Type(PackIndexing, Canonical,
computeDependence(Pattern, IndexExpr, Expansions)),
Context(Context), Pattern(Pattern), IndexExpr(IndexExpr),
Size(Expansions.size()), ExpandsToEmptyPack(ExpandsToEmptyPack) {
Size(Expansions.size()), FullySubstituted(FullySubstituted) {

std::uninitialized_copy(Expansions.begin(), Expansions.end(),
getTrailingObjects<QualType>());
Expand Down Expand Up @@ -4081,10 +4081,10 @@ PackIndexingType::computeDependence(QualType Pattern, Expr *IndexExpr,

void PackIndexingType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context, QualType Pattern,
Expr *E, bool ExpandsToEmptyPack) {
Expr *E, bool FullySubstituted) {
Pattern.Profile(ID);
E->Profile(ID, Context, true);
ID.AddBoolean(ExpandsToEmptyPack);
ID.AddBoolean(FullySubstituted);
}

UnaryTransformType::UnaryTransformType(QualType BaseType,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>

const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
const internal::VariadicDynCastAllOfMatcher<Decl, ExportDecl> exportDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl>
cxxConstructorDecl;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Analysis/Consumed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,9 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,

if (const auto *IfNode =
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
if (IfNode->isConsteval())
return false;

const Expr *Cond = IfNode->getCond();

PInfo = Visitor.getInfo(Cond);
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
Expand Down Expand Up @@ -282,6 +283,28 @@ ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
Visitor.traverseConstructorInits(CtorDecl);

// If analyzing a lambda call operator, collect all captures of parameters (of
// the surrounding function). This collects them even if they are not
// referenced in the body of the lambda call operator. Non-parameter local
// variables that are captured are already collected into
// `ReferencedDecls.Locals` when traversing the call operator body, but we
// collect parameters here to avoid needing to check at each referencing node
// whether the parameter is a lambda capture from a surrounding function or is
// a parameter of the current function. If it becomes necessary to limit this
// set to the parameters actually referenced in the body, alternative
// optimizations can be implemented to minimize duplicative work.
if (const auto *Method = dyn_cast<CXXMethodDecl>(&FD);
Method && isLambdaCallOperator(Method)) {
for (const auto &Capture : Method->getParent()->captures()) {
if (Capture.capturesVariable()) {
if (const auto *Param =
dyn_cast<ParmVarDecl>(Capture.getCapturedVar())) {
Result.LambdaCapturedParams.insert(Param);
}
}
}
}

return Result;
}

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/FlowSensitive/Arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ canonicalFormulaPair(const Formula &LHS, const Formula &RHS) {
}

template <class Key, class ComputeFunc>
const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,
ComputeFunc &&Compute) {
static const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,
ComputeFunc &&Compute) {
auto [It, Inserted] = Cache.try_emplace(std::forward<Key>(K));
if (Inserted)
It->second = Compute();
Expand Down
14 changes: 8 additions & 6 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
// expression must map to the same location / value. This is the case if we are
// performing a join for control flow within a full-expression (which is the
// only case when this function should be used).
template <typename MapT> MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
template <typename MapT>
static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
MapT Result = Map1;

for (const auto &Entry : Map2) {
Expand Down Expand Up @@ -204,10 +205,11 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev,
// Returns whether the values in `Map1` and `Map2` compare equal for those
// keys that `Map1` and `Map2` have in common.
template <typename Key>
bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
const llvm::MapVector<Key, Value *> &Map2,
const Environment &Env1, const Environment &Env2,
Environment::ValueModel &Model) {
static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
const llvm::MapVector<Key, Value *> &Map2,
const Environment &Env1,
const Environment &Env2,
Environment::ValueModel &Model) {
for (auto &Entry : Map1) {
Key K = Entry.first;
assert(K != nullptr);
Expand Down Expand Up @@ -260,7 +262,7 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
// Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
// `const StorageLocation *` or `const Expr *`.
template <typename Key>
llvm::MapVector<Key, Value *>
static llvm::MapVector<Key, Value *>
widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
const llvm::MapVector<Key, Value *> &PrevMap,
Environment &CurEnv, const Environment &PrevEnv,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ namespace dataflow {

/// Determines whether `D` is one of the methods used to implement Chromium's
/// `CHECK` macros. Populates `CheckDecls`, if empty.
bool isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
const CXXMethodDecl &D) {
static bool
isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
const CXXMethodDecl &D) {
// All of the methods of interest are static, so avoid any lookup for
// non-static methods (the common case).
if (!D.isStatic())
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Analysis/IntervalPartition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static unsigned getID(const CFGIntervalNode &I) { return I.ID; }

// `Node` must be one of `CFGBlock` or `CFGIntervalNode`.
template <typename Node>
BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
const Node *Header) {
static BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
const Node *Header) {
assert(Header != nullptr);
BuildResult<Node> Interval;
Interval.Nodes.push_back(Header);
Expand Down Expand Up @@ -102,10 +102,10 @@ BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
}

template <typename Node>
void fillIntervalNode(CFGIntervalGraph &Graph,
std::vector<CFGIntervalNode *> &Index,
std::queue<const Node *> &Successors,
llvm::BitVector &Partitioned, const Node *Header) {
static void fillIntervalNode(CFGIntervalGraph &Graph,
std::vector<CFGIntervalNode *> &Index,
std::queue<const Node *> &Successors,
llvm::BitVector &Partitioned, const Node *Header) {
BuildResult<Node> Result = buildInterval(Partitioned, Header);
for (const auto *S : Result.Successors)
Successors.push(S);
Expand Down Expand Up @@ -138,8 +138,8 @@ void fillIntervalNode(CFGIntervalGraph &Graph,
}

template <typename Node>
CFGIntervalGraph partitionIntoIntervalsImpl(unsigned NumBlockIDs,
const Node *EntryBlock) {
static CFGIntervalGraph partitionIntoIntervalsImpl(unsigned NumBlockIDs,
const Node *EntryBlock) {
assert(EntryBlock != nullptr);
CFGIntervalGraph Graph;
// `Index` maps all of the nodes of the input graph to the interval to which
Expand Down
130 changes: 84 additions & 46 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ class MatchDescendantVisitor : public DynamicRecursiveASTVisitor {
return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
}

bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override {
if (!TraverseStmt(Node->getExpr()))
return false;
return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
}

bool TraverseStmt(Stmt *Node) override {
if (!Node)
return true;
Expand Down Expand Up @@ -1987,14 +1993,18 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
};

/// Scan the function and return a list of gadgets found with provided kits.
static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
static void findGadgets(const Stmt *S, ASTContext &Ctx,
const UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions, FixableGadgetList &FixableGadgets,
WarningGadgetList &WarningGadgets,
DeclUseTracker &Tracker) {

struct GadgetFinderCallback : MatchFinder::MatchCallback {
FixableGadgetList FixableGadgets;
WarningGadgetList WarningGadgets;
DeclUseTracker Tracker;
GadgetFinderCallback(FixableGadgetList &FixableGadgets,
WarningGadgetList &WarningGadgets,
DeclUseTracker &Tracker)
: FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
Tracker(Tracker) {}

void run(const MatchFinder::MatchResult &Result) override {
// In debug mode, assert that we've found exactly one gadget.
Expand Down Expand Up @@ -2035,10 +2045,14 @@ findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
assert(numFound >= 1 && "Gadgets not found in match result!");
assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
}

FixableGadgetList &FixableGadgets;
WarningGadgetList &WarningGadgets;
DeclUseTracker &Tracker;
};

MatchFinder M;
GadgetFinderCallback CB;
GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};

// clang-format off
M.addMatcher(
Expand Down Expand Up @@ -2083,9 +2097,7 @@ findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
// clang-format on
}

M.match(*D->getBody(), D->getASTContext());
return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
std::move(CB.Tracker)};
M.match(*S, Ctx);
}

// Compares AST nodes by source locations.
Expand Down Expand Up @@ -2326,7 +2338,8 @@ static StringRef getEndOfLine() {
}

// Returns the text indicating that the user needs to provide input there:
std::string getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
static std::string
getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
std::string s = std::string("<# ");
s += HintTextToUser;
s += " #>";
Expand Down Expand Up @@ -3629,39 +3642,9 @@ class VariableGroupsManagerImpl : public VariableGroupsManager {
}
};

void clang::checkUnsafeBufferUsage(const Decl *D,
UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
#ifndef NDEBUG
Handler.clearDebugNotes();
#endif

assert(D && D->getBody());
// We do not want to visit a Lambda expression defined inside a method
// independently. Instead, it should be visited along with the outer method.
// FIXME: do we want to do the same thing for `BlockDecl`s?
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
return;
}

// Do not emit fixit suggestions for functions declared in an
// extern "C" block.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
for (FunctionDecl *FReDecl : FD->redecls()) {
if (FReDecl->isExternC()) {
EmitSuggestions = false;
break;
}
}
}

WarningGadgetSets UnsafeOps;
FixableGadgetSets FixablesForAllVars;

auto [FixableGadgets, WarningGadgets, Tracker] =
findGadgets(D, Handler, EmitSuggestions);

void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets,
WarningGadgetList WarningGadgets, DeclUseTracker Tracker,
UnsafeBufferUsageHandler &Handler, bool EmitSuggestions) {
if (!EmitSuggestions) {
// Our job is very easy without suggestions. Just warn about
// every problematic operation and consider it done. No need to deal
Expand Down Expand Up @@ -3705,8 +3688,10 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
if (WarningGadgets.empty())
return;

UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
FixablesForAllVars = groupFixablesByVar(std::move(FixableGadgets));
WarningGadgetSets UnsafeOps =
groupWarningGadgetsByVar(std::move(WarningGadgets));
FixableGadgetSets FixablesForAllVars =
groupFixablesByVar(std::move(FixableGadgets));

std::map<const VarDecl *, FixItList> FixItsForVariableGroup;

Expand Down Expand Up @@ -3927,3 +3912,56 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
}
}
}

void clang::checkUnsafeBufferUsage(const Decl *D,
UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
#ifndef NDEBUG
Handler.clearDebugNotes();
#endif

assert(D);

SmallVector<Stmt *> Stmts;

if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// We do not want to visit a Lambda expression defined inside a method
// independently. Instead, it should be visited along with the outer method.
// FIXME: do we want to do the same thing for `BlockDecl`s?
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
return;
}

for (FunctionDecl *FReDecl : FD->redecls()) {
if (FReDecl->isExternC()) {
// Do not emit fixit suggestions for functions declared in an
// extern "C" block.
EmitSuggestions = false;
break;
}
}

Stmts.push_back(FD->getBody());

if (const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
for (const CXXCtorInitializer *CI : ID->inits()) {
Stmts.push_back(CI->getInit());
}
}
} else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
Stmts.push_back(D->getBody());
}

assert(!Stmts.empty());

FixableGadgetList FixableGadgets;
WarningGadgetList WarningGadgets;
DeclUseTracker Tracker;
for (Stmt *S : Stmts) {
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
WarningGadgets, Tracker);
}
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
std::move(Tracker), Handler, EmitSuggestions);
}
Loading