[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:
Mark de Wever 2020-01-19 17:01:12 +01:00
parent 6b9a5e6f05
commit 41fcd17250
2 changed files with 78 additions and 0 deletions

View File

@ -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());

View File

@ -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