Skip to content

Commit d85806d

Browse files
authored
Merge branch 'llvm:main' into sirish/swdev-502377
2 parents 3327d88 + e3ef5f2 commit d85806d

File tree

12 files changed

+149
-58
lines changed

12 files changed

+149
-58
lines changed

clang-tools-extra/clang-tidy/bugprone/UncheckedOptionalAccessCheck.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
namespace clang::tidy::bugprone {
2020
using ast_matchers::MatchFinder;
2121
using dataflow::UncheckedOptionalAccessDiagnoser;
22+
using dataflow::UncheckedOptionalAccessDiagnostic;
2223
using dataflow::UncheckedOptionalAccessModel;
2324

2425
static constexpr llvm::StringLiteral FuncID("fun");
@@ -52,14 +53,16 @@ void UncheckedOptionalAccessCheck::check(
5253
UncheckedOptionalAccessDiagnoser Diagnoser(ModelOptions);
5354
// FIXME: Allow user to set the (defaulted) SAT iterations max for
5455
// `diagnoseFunction` with config options.
55-
if (llvm::Expected<llvm::SmallVector<SourceLocation>> Locs =
56-
dataflow::diagnoseFunction<UncheckedOptionalAccessModel,
57-
SourceLocation>(*FuncDecl, *Result.Context,
58-
Diagnoser))
59-
for (const SourceLocation &Loc : *Locs)
60-
diag(Loc, "unchecked access to optional value");
56+
if (llvm::Expected<llvm::SmallVector<UncheckedOptionalAccessDiagnostic>>
57+
Diags = dataflow::diagnoseFunction<UncheckedOptionalAccessModel,
58+
UncheckedOptionalAccessDiagnostic>(
59+
*FuncDecl, *Result.Context, Diagnoser))
60+
for (const UncheckedOptionalAccessDiagnostic &Diag : *Diags) {
61+
diag(Diag.Range.getBegin(), "unchecked access to optional value")
62+
<< Diag.Range;
63+
}
6164
else
62-
llvm::consumeError(Locs.takeError());
65+
llvm::consumeError(Diags.takeError());
6366
}
6467

6568
} // namespace clang::tidy::bugprone

clang/include/clang/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/Analysis/FlowSensitive/CachedConstAccessorsLattice.h"
2121
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
2222
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
23+
#include "clang/Analysis/FlowSensitive/MatchSwitch.h"
2324
#include "clang/Analysis/FlowSensitive/NoopLattice.h"
2425
#include "clang/Basic/SourceLocation.h"
2526
#include "llvm/ADT/SmallVector.h"
@@ -71,20 +72,26 @@ class UncheckedOptionalAccessModel
7172
TransferMatchSwitch;
7273
};
7374

75+
/// Diagnostic information for an unchecked optional access.
76+
struct UncheckedOptionalAccessDiagnostic {
77+
CharSourceRange Range;
78+
};
79+
7480
class UncheckedOptionalAccessDiagnoser {
7581
public:
7682
UncheckedOptionalAccessDiagnoser(
7783
UncheckedOptionalAccessModelOptions Options = {});
7884

79-
llvm::SmallVector<SourceLocation>
85+
llvm::SmallVector<UncheckedOptionalAccessDiagnostic>
8086
operator()(const CFGElement &Elt, ASTContext &Ctx,
8187
const TransferStateForDiagnostics<UncheckedOptionalAccessLattice>
8288
&State) {
8389
return DiagnoseMatchSwitch(Elt, Ctx, State.Env);
8490
}
8591

8692
private:
87-
CFGMatchSwitch<const Environment, llvm::SmallVector<SourceLocation>>
93+
CFGMatchSwitch<const Environment,
94+
llvm::SmallVector<UncheckedOptionalAccessDiagnostic>>
8895
DiagnoseMatchSwitch;
8996
};
9097

clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,8 +1120,8 @@ auto buildTransferMatchSwitch() {
11201120
.Build();
11211121
}
11221122

1123-
llvm::SmallVector<SourceLocation> diagnoseUnwrapCall(const Expr *ObjectExpr,
1124-
const Environment &Env) {
1123+
llvm::SmallVector<UncheckedOptionalAccessDiagnostic>
1124+
diagnoseUnwrapCall(const Expr *ObjectExpr, const Environment &Env) {
11251125
if (auto *OptionalLoc = cast_or_null<RecordStorageLocation>(
11261126
getLocBehindPossiblePointer(*ObjectExpr, Env))) {
11271127
auto *Prop = Env.getValue(locForHasValue(*OptionalLoc));
@@ -1132,9 +1132,9 @@ llvm::SmallVector<SourceLocation> diagnoseUnwrapCall(const Expr *ObjectExpr,
11321132
}
11331133

11341134
// Record that this unwrap is *not* provably safe.
1135-
// FIXME: include either the name of the optional (if applicable) or a source
1136-
// range of the access for easier interpretation of the result.
1137-
return {ObjectExpr->getBeginLoc()};
1135+
// FIXME: include the name of the optional (if applicable).
1136+
auto Range = CharSourceRange::getTokenRange(ObjectExpr->getSourceRange());
1137+
return {UncheckedOptionalAccessDiagnostic{Range}};
11381138
}
11391139

11401140
auto buildDiagnoseMatchSwitch(
@@ -1143,8 +1143,9 @@ auto buildDiagnoseMatchSwitch(
11431143
// lot of duplicated work (e.g. string comparisons), consider providing APIs
11441144
// that avoid it through memoization.
11451145
auto IgnorableOptional = ignorableOptional(Options);
1146-
return CFGMatchSwitchBuilder<const Environment,
1147-
llvm::SmallVector<SourceLocation>>()
1146+
return CFGMatchSwitchBuilder<
1147+
const Environment,
1148+
llvm::SmallVector<UncheckedOptionalAccessDiagnostic>>()
11481149
// optional::value
11491150
.CaseOfCFGStmt<CXXMemberCallExpr>(
11501151
valueCall(IgnorableOptional),

clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,7 @@ constexpr vector<T, L> reflect_vec_impl(vector<T, L> I, vector<T, L> N) {
5858
#endif
5959
}
6060

61-
template <typename T>
62-
constexpr enable_if_t<is_same<float, T>::value || is_same<half, T>::value, T>
63-
fmod_impl(T X, T Y) {
61+
template <typename T> constexpr T fmod_impl(T X, T Y) {
6462
#if !defined(__DIRECTX__)
6563
return __builtin_elementwise_fmod(X, Y);
6664
#else

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,19 +129,33 @@ const inline float distance(__detail::HLSL_FIXED_VECTOR<float, N> X,
129129
/// Return the floating-point remainder of the x parameter divided by the y
130130
/// parameter.
131131

132+
template <typename T>
132133
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
133-
const inline half fmod(half X, half Y) { return __detail::fmod_impl(X, Y); }
134+
const inline __detail::enable_if_t<__detail::is_arithmetic<T>::Value &&
135+
__detail::is_same<half, T>::value,
136+
T> fmod(T X, T Y) {
137+
return __detail::fmod_impl(X, Y);
138+
}
134139

135-
const inline float fmod(float X, float Y) { return __detail::fmod_impl(X, Y); }
140+
template <typename T>
141+
const inline __detail::enable_if_t<
142+
__detail::is_arithmetic<T>::Value && __detail::is_same<float, T>::value, T>
143+
fmod(T X, T Y) {
144+
return __detail::fmod_impl(X, Y);
145+
}
136146

137147
template <int N>
138148
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
139-
const inline vector<half, N> fmod(vector<half, N> X, vector<half, N> Y) {
149+
const inline __detail::HLSL_FIXED_VECTOR<half, N> fmod(
150+
__detail::HLSL_FIXED_VECTOR<half, N> X,
151+
__detail::HLSL_FIXED_VECTOR<half, N> Y) {
140152
return __detail::fmod_vec_impl(X, Y);
141153
}
142154

143155
template <int N>
144-
const inline vector<float, N> fmod(vector<float, N> X, vector<float, N> Y) {
156+
const inline __detail::HLSL_FIXED_VECTOR<float, N>
157+
fmod(__detail::HLSL_FIXED_VECTOR<float, N> X,
158+
__detail::HLSL_FIXED_VECTOR<float, N> Y) {
145159
return __detail::fmod_vec_impl(X, Y);
146160
}
147161

clang/test/SemaHLSL/BuiltIns/fmod-errors.hlsl

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,55 @@
33
float test_no_second_arg(float2 p0) {
44
return fmod(p0);
55
// expected-error@-1 {{no matching function for call to 'fmod'}}
6-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
7-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 1 was provided}}
6+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
7+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
88
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
99
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 1 was provided}}
1010
}
1111

1212
float test_too_many_arg(float2 p0) {
1313
return fmod(p0, p0, p0);
1414
// expected-error@-1 {{no matching function for call to 'fmod'}}
15-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
16-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function not viable: requires 2 arguments, but 3 were provided}}
15+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
16+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
1717
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
1818
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function template not viable: requires 2 arguments, but 3 were provided}}
1919
}
2020

2121
float test_double_inputs(double p0, double p1) {
2222
return fmod(p0, p1);
23-
// expected-error@-1 {{call to 'fmod' is ambiguous}}
24-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
25-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
23+
// expected-error@-1 {{no matching function for call to 'fmod'}}
24+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
25+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
26+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
27+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
2628
}
2729

2830
float test_int_inputs(int p0, int p1) {
2931
return fmod(p0, p1);
30-
// expected-error@-1 {{call to 'fmod' is ambiguous}}
31-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
32-
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate function}}
32+
// expected-error@-1 {{no matching function for call to 'fmod'}}
33+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
34+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
35+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
36+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored}}
37+
}
38+
39+
float1 test_vec1_inputs(float1 p0, float1 p1) {
40+
return fmod(p0, p1);
41+
// expected-error@-1 {{no matching function for call to 'fmod'}}
42+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
43+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 1>>'}}
44+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
45+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 1]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
46+
}
47+
48+
typedef float float5 __attribute__((ext_vector_type(5)));
49+
50+
float5 test_vec5_inputs(float5 p0, float5 p1) {
51+
return fmod(p0, p1);
52+
// expected-error@-1 {{no matching function for call to 'fmod'}}
53+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
54+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with T = float5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, vector<float, 5>>'}}
55+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, half>'}}
56+
// expected-note@hlsl/hlsl_intrinsics.h:* {{candidate template ignored: substitution failure [with N = 5]: no type named 'Type' in 'hlsl::__detail::enable_if<false, float>'}}
3357
}

clang/unittests/Analysis/FlowSensitive/UncheckedOptionalAccessModelTest.cpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/Basic/SourceLocation.h"
1515
#include "clang/Frontend/TextDiagnostic.h"
1616
#include "clang/Tooling/Tooling.h"
17+
#include "llvm/ADT/DenseMap.h"
1718
#include "llvm/ADT/DenseSet.h"
1819
#include "llvm/ADT/STLExtras.h"
1920
#include "llvm/Support/Error.h"
@@ -1282,6 +1283,14 @@ static raw_ostream &operator<<(raw_ostream &OS,
12821283
class UncheckedOptionalAccessTest
12831284
: public ::testing::TestWithParam<OptionalTypeIdentifier> {
12841285
protected:
1286+
// Check that after running the analysis on SourceCode, it produces the
1287+
// expected diagnostics according to [[unsafe]] annotations.
1288+
// - No annotations => no diagnostics.
1289+
// - Given "// [[unsafe]]" annotations on a line, we expect a diagnostic on
1290+
// that line.
1291+
// - Given "// [[unsafe:range_text]]" annotations on a line, we expect a
1292+
// diagnostic on that line, and we expect the diagnostic Range (printed as
1293+
// a string) to match the "range_text".
12851294
void ExpectDiagnosticsFor(std::string SourceCode,
12861295
bool IgnoreSmartPointerDereference = true) {
12871296
ExpectDiagnosticsFor(SourceCode, ast_matchers::hasName("target"),
@@ -1336,7 +1345,7 @@ class UncheckedOptionalAccessTest
13361345
T Make();
13371346
)");
13381347
UncheckedOptionalAccessModelOptions Options{IgnoreSmartPointerDereference};
1339-
std::vector<SourceLocation> Diagnostics;
1348+
std::vector<UncheckedOptionalAccessDiagnostic> Diagnostics;
13401349
llvm::Error Error = checkDataflow<UncheckedOptionalAccessModel>(
13411350
AnalysisInputs<UncheckedOptionalAccessModel>(
13421351
SourceCode, std::move(FuncMatcher),
@@ -1364,22 +1373,34 @@ class UncheckedOptionalAccessTest
13641373
&Annotations,
13651374
const AnalysisOutputs &AO) {
13661375
llvm::DenseSet<unsigned> AnnotationLines;
1367-
for (const auto &[Line, _] : Annotations) {
1376+
llvm::DenseMap<unsigned, std::string> AnnotationRangesInLines;
1377+
for (const auto &[Line, AnnotationWithMaybeRange] : Annotations) {
13681378
AnnotationLines.insert(Line);
1379+
auto it = AnnotationWithMaybeRange.find(':');
1380+
if (it != std::string::npos) {
1381+
AnnotationRangesInLines[Line] =
1382+
AnnotationWithMaybeRange.substr(it + 1);
1383+
}
13691384
}
13701385
auto &SrcMgr = AO.ASTCtx.getSourceManager();
13711386
llvm::DenseSet<unsigned> DiagnosticLines;
1372-
for (SourceLocation &Loc : Diagnostics) {
1373-
unsigned Line = SrcMgr.getPresumedLineNumber(Loc);
1387+
for (const UncheckedOptionalAccessDiagnostic &Diag : Diagnostics) {
1388+
unsigned Line = SrcMgr.getPresumedLineNumber(Diag.Range.getBegin());
13741389
DiagnosticLines.insert(Line);
13751390
if (!AnnotationLines.contains(Line)) {
13761391
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(
13771392
new DiagnosticOptions());
13781393
TextDiagnostic TD(llvm::errs(), AO.ASTCtx.getLangOpts(),
13791394
DiagOpts.get());
1380-
TD.emitDiagnostic(FullSourceLoc(Loc, SrcMgr),
1395+
TD.emitDiagnostic(FullSourceLoc(Diag.Range.getBegin(), SrcMgr),
13811396
DiagnosticsEngine::Error,
1382-
"unexpected diagnostic", {}, {});
1397+
"unexpected diagnostic", {Diag.Range}, {});
1398+
} else {
1399+
auto it = AnnotationRangesInLines.find(Line);
1400+
if (it != AnnotationRangesInLines.end()) {
1401+
EXPECT_EQ(Diag.Range.getAsRange().printToString(SrcMgr),
1402+
it->second);
1403+
}
13831404
}
13841405
}
13851406

@@ -4085,6 +4106,31 @@ TEST_P(UncheckedOptionalAccessTest, ConstPointerRefAccessor) {
40854106
/*IgnoreSmartPointerDereference=*/false);
40864107
}
40874108

4109+
TEST_P(UncheckedOptionalAccessTest, DiagnosticsHaveRanges) {
4110+
ExpectDiagnosticsFor(R"cc(
4111+
#include "unchecked_optional_access_test.h"
4112+
4113+
struct A {
4114+
$ns::$optional<int> fi;
4115+
};
4116+
struct B {
4117+
$ns::$optional<A> fa;
4118+
};
4119+
4120+
void target($ns::$optional<B> opt) {
4121+
opt.value(); // [[unsafe:<input.cc:12:7>]]
4122+
if (opt) {
4123+
opt // [[unsafe:<input.cc:14:9, line:16:13>]]
4124+
->
4125+
fa.value();
4126+
if (opt->fa) {
4127+
opt->fa->fi.value(); // [[unsafe:<input.cc:18:11, col:20>]]
4128+
}
4129+
}
4130+
}
4131+
)cc");
4132+
}
4133+
40884134
// FIXME: Add support for:
40894135
// - constructors (copy, move)
40904136
// - assignment operators (default, copy, move)

llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -690,12 +690,10 @@ static constexpr DecoderListEntry DecoderList32[]{
690690
{DecoderTableXCV32, XCVFeatureGroup, "CORE-V extensions"},
691691
{DecoderTableXqci32, XqciFeatureGroup, "Qualcomm uC Extensions"},
692692
{DecoderTableXRivos32, XRivosFeatureGroup, "Rivos"},
693-
{DecoderTable32, {}, "RISCV32"},
694-
{DecoderTableRV32GPRPair32, {}, "RV32GPRPair (rv32 and GPR pairs)"},
693+
{DecoderTable32, {}, "standard 32-bit instructions"},
694+
{DecoderTableRV32Only32, {}, "RV32-only standard 32-bit instructions"},
695695
{DecoderTableZfinx32, {}, "Zfinx (Float in Integer)"},
696-
{DecoderTableZdinxRV32GPRPair32,
697-
{},
698-
"ZdinxRV32GPRPair (rv32 and Double in Integer)"},
696+
{DecoderTableZdinxRV32Only32, {}, "RV32-only Zdinx (Double in Integer)"},
699697
};
700698

701699
DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
@@ -714,7 +712,7 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
714712
if (!Entry.haveContainedFeatures(STI.getFeatureBits()))
715713
continue;
716714

717-
LLVM_DEBUG(dbgs() << "Trying " << Entry.Desc << "table:\n");
715+
LLVM_DEBUG(dbgs() << "Trying " << Entry.Desc << " table:\n");
718716
DecodeStatus Result =
719717
decodeInstruction(Entry.Table, MI, Insn, Address, this, STI);
720718
if (Result == MCDisassembler::Fail)
@@ -728,16 +726,16 @@ DecodeStatus RISCVDisassembler::getInstruction32(MCInst &MI, uint64_t &Size,
728726

729727
static constexpr DecoderListEntry DecoderList16[]{
730728
// Vendor Extensions
731-
{DecoderTableXqci16, XqciFeatureGroup, "Qualcomm uC 16bit"},
729+
{DecoderTableXqci16, XqciFeatureGroup, "Qualcomm uC 16-bit"},
732730
{DecoderTableXqccmp16,
733731
{RISCV::FeatureVendorXqccmp},
734732
"Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)"},
735733
{DecoderTableXwchc16, {RISCV::FeatureVendorXwchc}, "WCH QingKe XW"},
736734
// Standard Extensions
737735
// DecoderTableZicfiss16 must be checked before DecoderTable16.
738-
{DecoderTableZicfiss16, {}, "RVZicfiss (Shadow Stack)"},
739-
{DecoderTable16, {}, "RISCV_C (16-bit Instruction)"},
740-
{DecoderTableRISCV32Only_16, {}, "RISCV32Only_16 (16-bit Instruction)"},
736+
{DecoderTableZicfiss16, {}, "Zicfiss (Shadow Stack 16-bit)"},
737+
{DecoderTable16, {}, "standard 16-bit instructions"},
738+
{DecoderTableRV32Only16, {}, "RV32-only 16-bit instructions"},
741739
// Zc* instructions incompatible with Zcf or Zcd
742740
{DecoderTableZcOverlap16,
743741
{},

0 commit comments

Comments
 (0)