From 41fcd17250fa0526e4b7fd2c7df7721b0f79b683 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 19 Jan 2020 17:01:12 +0100 Subject: [PATCH] [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 --- clang/lib/Sema/SemaStmt.cpp | 6 ++ .../test/SemaCXX/warn-range-loop-analysis.cpp | 72 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d6c3af9e84c8..ff6481006280 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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()); diff --git a/clang/test/SemaCXX/warn-range-loop-analysis.cpp b/clang/test/SemaCXX/warn-range-loop-analysis.cpp index 53b0ca288194..951844c953ef 100644 --- a/clang/test/SemaCXX/warn-range-loop-analysis.cpp +++ b/clang/test/SemaCXX/warn-range-loop-analysis.cpp @@ -454,3 +454,75 @@ void test10() { // expected-note@-2 {{'Bar'}} // CHECK: fix-it:"{{.*}}":{[[@LINE-3]]:17-[[@LINE-3]]:18}:" " } + +template +void test_template_function() { + // In a template instantiation the diagnostics should not be emitted for + // loops with dependent types. + Container 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 Dependent; + for (const T &x : Dependent) {} +} +template void test_template_function(); + +template +struct test_template_struct { + static void static_member() { + Container 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 Dependent; + for (const T &x : Dependent) {} + } + + void member() { + Container 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 Dependent; + for (const T &x : Dependent) {} + } +}; +template struct test_template_struct; + +struct test_struct_with_templated_member { + void member() { + Container 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 + void template_member() { + Container 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 Dependent; + for (const T &x : Dependent) {} + } +}; +template void test_struct_with_templated_member::template_member(); + +#define TEST_MACRO \ + void test_macro() { \ + Container C; \ + for (const Bar &x : C) {} \ + } + +TEST_MACRO