// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage \
// RUN: -fsafe-buffer-usage-suggestions \
// RUN: -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s
void basic(int * x) {
int tmp;
int *p1 = new int[10]; // no fix
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int *p2 = new int[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
#pragma clang unsafe_buffer_usage begin
tmp = p1[5];
#pragma clang unsafe_buffer_usage end
tmp = p2[5];
}
void withDiagnosticWarning() {
int tmp;
int *p1 = new int[10]; // no fix
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int *p2 = new int[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
// diagnostics in opt-out region
#pragma clang unsafe_buffer_usage begin
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic push
#pragma clang diagnostic warning "-Wunsafe-buffer-usage"
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic warning "-Weverything"
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic pop
#pragma clang unsafe_buffer_usage end
// opt-out region under diagnostic warning
#pragma clang diagnostic push
#pragma clang diagnostic warning "-Wunsafe-buffer-usage"
#pragma clang unsafe_buffer_usage begin
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang unsafe_buffer_usage end
#pragma clang diagnostic pop
tmp = p2[5];
}
void withDiagnosticIgnore() {
int tmp;
int *p1 = new int[10];
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int *p2 = new int[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
int *p3 = new int[10];
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int> "
// CHECK: fix-it:"{{.*}}":{[[@LINE-2]]:13-[[@LINE-2]]:13}:"{"
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:24-[[@LINE-3]]:24}:", 10}"
#pragma clang unsafe_buffer_usage begin
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic ignored "-Weverything"
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang diagnostic pop
#pragma clang unsafe_buffer_usage end
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#pragma clang unsafe_buffer_usage begin
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang unsafe_buffer_usage end
#pragma clang diagnostic pop
tmp = p2[5];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#pragma clang unsafe_buffer_usage begin
tmp = p1[5]; // not to warn
tmp = p2[5]; // not to warn
#pragma clang unsafe_buffer_usage end
tmp = p3[5]; // expected-note{{used in buffer access here}}
#pragma clang diagnostic pop
}
void noteGoesWithVarDeclWarning() {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
int *p = new int[10]; // not to warn
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
#pragma clang diagnostic pop
p[5]; // not to note since the associated warning is suppressed
}
// Test suppressing interacts with variable grouping:
// The implication edges are: `a` -> `b` -> `c`.
// If the unsafe operation on `a` is supressed, none of the variables
// will be fixed.
void suppressedVarInGroup() {
int * a;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * b;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * c;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
#pragma clang unsafe_buffer_usage begin
a[5] = 5;
#pragma clang unsafe_buffer_usage end
a = b;
b = c;
}
// To show that if `a[5]` is not suppressed in the
// `suppressedVarInGroup` function above, all variables will be fixed.
void suppressedVarInGroup_control() {
int * a;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * b;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * c;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
a[5] = 5;
a = b;
b = c;
}
// The implication edges are: `a` -> `b` -> `c`.
// The unsafe operation on `b` is supressed, while the unsafe
// operation on `a` is not suppressed. Variable `b` will still be
// fixed when fixing `a`.
void suppressedVarInGroup2() {
int * a;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * b;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * c;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
a[5] = 5;
#pragma clang unsafe_buffer_usage begin
b[5] = 5;
#pragma clang unsafe_buffer_usage end
a = b;
b = c;
}
// The implication edges are: `a` -> `b` -> `c`.
// The unsafe operation on `b` is supressed, while the unsafe
// operation on `c` is not suppressed. Only variable `c` will be fixed
// then.
void suppressedVarInGroup3() {
int * a;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * b;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * c;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
c[5] = 5;
#pragma clang unsafe_buffer_usage begin
b[5] = 5;
#pragma clang unsafe_buffer_usage end
a = b;
b = c;
// FIXME: we do not fix `a = b` and `b = c` because the `.data()` fix-it is not generally correct.
}
// The implication edges are: `a` -> `b` -> `c` -> `a`.
// The unsafe operation on `b` is supressed, while the unsafe
// operation on `c` is not suppressed. Since the implication graph
// forms a cycle, all variables will be fixed.
void suppressedVarInGroup4() {
int * a;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * b;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * c;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
c[5] = 5;
#pragma clang unsafe_buffer_usage begin
b[5] = 5;
#pragma clang unsafe_buffer_usage end
a = b;
b = c;
c = a;
}
// There are two groups: `a` -> `b` -> `c` and `d` -> `e` -> `f`.
// Suppressing unsafe operations on variables in one group does not
// affect other groups.
void suppressedVarInGroup5() {
int * a;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * b;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * c;
// CHECK-NOT: fix-it:"{{.*}}":{[[@LINE-1]]:
int * d;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * e;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
int * f;
// CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:3-[[@LINE-1]]:8}:"std::span<int>"
#pragma clang unsafe_buffer_usage begin
a[5] = 5;
#pragma clang unsafe_buffer_usage end
a = b;
b = c;
d[5] = 5;
d = e;
e = f;
}