Commit 6874dfce authored by Nathan's avatar Nathan
Browse files

[clang-tidy] Fix bugprone-use-after-move when move is in noexcept operator

Summary: Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=44667 | noexcept operator misinterpreted as being evaluated ]].

Reviewers: aaron.ballman, alexfh, JonasToth, hokein, gribozavr2

Reviewed By: gribozavr2

Subscribers: merge_guards_bot, Quuxplusone, xazax.hun, cfe-commits

Tags: #clang, #clang-tools-extra

Differential Revision: https://reviews.llvm.org/D73441
parent c7c5da6d
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -8,6 +8,10 @@

#include "UseAfterMoveCheck.h"

#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/CFG.h"
#include "clang/Lex/Lexer.h"

@@ -23,6 +27,23 @@ namespace bugprone {

namespace {

AST_MATCHER(Expr, hasUnevaluatedContext) {
  if (isa<CXXNoexceptExpr>(Node) || isa<RequiresExpr>(Node))
    return true;
  if (const auto *UnaryExpr = dyn_cast<UnaryExprOrTypeTraitExpr>(&Node)) {
    switch (UnaryExpr->getKind()) {
    case UETT_SizeOf:
    case UETT_AlignOf:
      return true;
    default:
      return false;
    }
  }
  if (const auto *TypeIDExpr = dyn_cast<CXXTypeidExpr>(&Node))
    return !TypeIDExpr->isPotentiallyEvaluated();
  return false;
}

/// Contains information about a use-after-move.
struct UseAfterMove {
  // The DeclRefExpr that constituted the use of the object.
@@ -77,7 +98,8 @@ private:
static StatementMatcher inDecltypeOrTemplateArg() {
  return anyOf(hasAncestor(typeLoc()),
               hasAncestor(declRefExpr(
                   to(functionDecl(ast_matchers::isTemplateInstantiation())))));
                   to(functionDecl(ast_matchers::isTemplateInstantiation())))),
               hasAncestor(expr(hasUnevaluatedContext())));
}

UseAfterMoveFinder::UseAfterMoveFinder(ASTContext *TheContext)
+28 −0
Original line number Diff line number Diff line
@@ -1270,4 +1270,32 @@ class C : T, B {
    C c;
  }
};
}
} // namespace PR33020

namespace UnevalContext {
struct Foo {};
void noExcept() {
  Foo Bar;
  (void) noexcept(Foo{std::move(Bar)});
  Foo Other{std::move(Bar)};
}
void sizeOf() {
  Foo Bar;
  (void)sizeof(Foo{std::move(Bar)});
  Foo Other{std::move(Bar)};
}
void alignOf() {
  Foo Bar;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-alignof-expression"
  (void)alignof(Foo{std::move(Bar)});
#pragma clang diagnostic pop
  Foo Other{std::move(Bar)};
}
void typeId() {
  Foo Bar;
  // error: you need to include <typeinfo> before using the 'typeid' operator
  // (void) typeid(Foo{std::move(Bar)}).name();
  Foo Other{std::move(Bar)};
}
} // namespace UnevalContext