Commit 41fcd172 authored by Mark de Wever's avatar Mark de Wever
Browse files

[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
parent 6b9a5e6f
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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());
+72 −0
Original line number Diff line number Diff line
@@ -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