forked from OSchip/llvm-project
[Sema] Avoid Wrange-loop-analysis false positives
When Wrange-loop-analysis issues a diagnostic on a dependent type in a template the diagnostic may not be valid for all instantiations. Therefore the diagnostic is suppressed during the instantiation. Non dependent types still issue a diagnostic. The same can happen when using macros. Therefore the diagnostic is disabled for macros. Fixes https://bugs.llvm.org/show_bug.cgi?id=44556 Differential Revision: https://reviews.llvm.org/D73007
This commit is contained in:
parent
6b9a5e6f05
commit
41fcd17250
|
@ -2838,6 +2838,9 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef,
|
|||
/// Suggest "const foo &x" to prevent the copy.
|
||||
static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
|
||||
const CXXForRangeStmt *ForStmt) {
|
||||
if (SemaRef.inTemplateInstantiation())
|
||||
return;
|
||||
|
||||
if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy,
|
||||
ForStmt->getBeginLoc()) &&
|
||||
SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy,
|
||||
|
@ -2860,6 +2863,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef,
|
|||
if (!InitExpr)
|
||||
return;
|
||||
|
||||
if (InitExpr->getExprLoc().isMacroID())
|
||||
return;
|
||||
|
||||
if (VariableType->isReferenceType()) {
|
||||
DiagnoseForRangeReferenceVariableCopies(SemaRef, VD,
|
||||
ForStmt->getRangeInit()->getType());
|
||||
|
|
|
@ -454,3 +454,75 @@ void test10() {
|
|||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:" "
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_template_function() {
|
||||
// In a template instantiation the diagnostics should not be emitted for
|
||||
// loops with dependent types.
|
||||
Container<Bar> C;
|
||||
for (const Bar &x : C) {}
|
||||
// expected-warning@-1 {{always a copy}}
|
||||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:18-[[@LINE-3]]:19}:""
|
||||
|
||||
Container<T> Dependent;
|
||||
for (const T &x : Dependent) {}
|
||||
}
|
||||
template void test_template_function<Bar>();
|
||||
|
||||
template <class T>
|
||||
struct test_template_struct {
|
||||
static void static_member() {
|
||||
Container<Bar> C;
|
||||
for (const Bar &x : C) {}
|
||||
// expected-warning@-1 {{always a copy}}
|
||||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:""
|
||||
|
||||
Container<T> Dependent;
|
||||
for (const T &x : Dependent) {}
|
||||
}
|
||||
|
||||
void member() {
|
||||
Container<Bar> C;
|
||||
for (const Bar &x : C) {}
|
||||
// expected-warning@-1 {{always a copy}}
|
||||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:""
|
||||
|
||||
Container<T> Dependent;
|
||||
for (const T &x : Dependent) {}
|
||||
}
|
||||
};
|
||||
template struct test_template_struct<Bar>;
|
||||
|
||||
struct test_struct_with_templated_member {
|
||||
void member() {
|
||||
Container<Bar> C;
|
||||
for (const Bar &x : C) {}
|
||||
// expected-warning@-1 {{always a copy}}
|
||||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:""
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void template_member() {
|
||||
Container<Bar> C;
|
||||
for (const Bar &x : C) {}
|
||||
// expected-warning@-1 {{always a copy}}
|
||||
// expected-note@-2 {{'Bar'}}
|
||||
// CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:20-[[@LINE-3]]:21}:""
|
||||
|
||||
Container<T> Dependent;
|
||||
for (const T &x : Dependent) {}
|
||||
}
|
||||
};
|
||||
template void test_struct_with_templated_member::template_member<Bar>();
|
||||
|
||||
#define TEST_MACRO \
|
||||
void test_macro() { \
|
||||
Container<Bar> C; \
|
||||
for (const Bar &x : C) {} \
|
||||
}
|
||||
|
||||
TEST_MACRO
|
||||
|
|
Loading…
Reference in New Issue