[OPENMP][C++20]Add support for CXXRewrittenBinaryOperator in ranged for loops.

Added support for CXXRewrittenBinaryOperator as a condition in ranged
for loops. This is a new kind of expression, need to extend support for
  C++20 constructs.
It fixes PR49970: range-based for compilation fails for libstdc++ vector
with -std=c++20.

Differential Revision: https://reviews.llvm.org/D104240
This commit is contained in:
Alexey Bataev 2021-06-14 06:03:42 -07:00
parent a490ca8e01
commit 4e15560879
2 changed files with 73 additions and 43 deletions

View File

@ -7668,53 +7668,43 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
if (BO->isRelationalOp()) {
if (getInitLCDecl(BO->getLHS()) == LCDecl)
return setUB(BO->getRHS(),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
if (getInitLCDecl(BO->getRHS()) == LCDecl)
return setUB(BO->getLHS(),
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
} else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE)
return setUB(
getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(),
/*LessOp=*/llvm::None,
/*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc());
auto &&CheckAndSetCond = [this, IneqCondIsCanonical](
BinaryOperatorKind Opcode, const Expr *LHS,
const Expr *RHS, SourceRange SR,
SourceLocation OpLoc) -> llvm::Optional<bool> {
if (BinaryOperator::isRelationalOp(Opcode)) {
if (getInitLCDecl(LHS) == LCDecl)
return setUB(const_cast<Expr *>(RHS),
(Opcode == BO_LT || Opcode == BO_LE),
(Opcode == BO_LT || Opcode == BO_GT), SR, OpLoc);
if (getInitLCDecl(RHS) == LCDecl)
return setUB(const_cast<Expr *>(LHS),
(Opcode == BO_GT || Opcode == BO_GE),
(Opcode == BO_LT || Opcode == BO_GT), SR, OpLoc);
} else if (IneqCondIsCanonical && Opcode == BO_NE) {
return setUB(const_cast<Expr *>(getInitLCDecl(LHS) == LCDecl ? RHS : LHS),
/*LessOp=*/llvm::None,
/*StrictOp=*/true, SR, OpLoc);
}
return llvm::None;
};
llvm::Optional<bool> Res;
if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) {
CXXRewrittenBinaryOperator::DecomposedForm DF = RBO->getDecomposedForm();
Res = CheckAndSetCond(DF.Opcode, DF.LHS, DF.RHS, RBO->getSourceRange(),
RBO->getOperatorLoc());
} else if (auto *BO = dyn_cast<BinaryOperator>(S)) {
Res = CheckAndSetCond(BO->getOpcode(), BO->getLHS(), BO->getRHS(),
BO->getSourceRange(), BO->getOperatorLoc());
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getNumArgs() == 2) {
auto Op = CE->getOperator();
switch (Op) {
case OO_Greater:
case OO_GreaterEqual:
case OO_Less:
case OO_LessEqual:
if (getInitLCDecl(CE->getArg(0)) == LCDecl)
return setUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
if (getInitLCDecl(CE->getArg(1)) == LCDecl)
return setUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
break;
case OO_ExclaimEqual:
if (IneqCondIsCanonical)
return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1)
: CE->getArg(0),
/*LessOp=*/llvm::None,
/*StrictOp=*/true, CE->getSourceRange(),
CE->getOperatorLoc());
break;
default:
break;
}
Res = CheckAndSetCond(
BinaryOperator::getOverloadedOpcode(CE->getOperator()), CE->getArg(0),
CE->getArg(1), CE->getSourceRange(), CE->getOperatorLoc());
}
}
if (Res.hasValue())
return *Res;
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)

View File

@ -0,0 +1,40 @@
// RUN: %clang_cc1 -verify -fopenmp --std=c++20 -ast-print %s -Wsign-conversion | FileCheck %s
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++20 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -std=c++20 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// RUN: %clang_cc1 -verify -fopenmp-simd --std=c++20 -ast-print %s -Wsign-conversion | FileCheck %s
// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++20 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp-simd -std=c++20 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
template <typename T> class iterator {
public:
T &operator*() const;
iterator &operator++();
};
template <typename T>
bool operator==(const iterator<T> &, const iterator<T> &);
template <typename T>
unsigned long operator-(const iterator<T> &, const iterator<T> &);
template <typename T>
iterator<T> operator+(const iterator<T> &, unsigned long);
class vector {
public:
vector();
iterator<int> begin();
iterator<int> end();
};
// CHECK: void foo() {
void foo() {
// CHECK-NEXT: vector vec;
vector vec;
// CHECK-NEXT: #pragma omp for
#pragma omp for
// CHECK-NEXT: for (int i : vec)
for (int i : vec)
;
}
#endif