Skip to content

Commit b819c4e

Browse files
committed
Merge from 'main' to 'sycl-web' (25 commits)
CONFLICT (content): Merge conflict in llvm/lib/Target/NVPTX/NVPTXTargetMachine.cpp
2 parents 57deb60 + a88d580 commit b819c4e

File tree

92 files changed

+1679
-814
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1679
-814
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ Improvements to Clang's diagnostics
389389
under the subgroup ``-Wunsafe-buffer-usage-in-libc-call``.
390390
- Diagnostics on chained comparisons (``a < b < c``) are now an error by default. This can be disabled with
391391
``-Wno-error=parentheses``.
392+
- Similarly, fold expressions over a comparison operator are now an error by default.
392393
- Clang now better preserves the sugared types of pointers to member.
393394
- Clang now better preserves the presence of the template keyword with dependent
394395
prefixes.

clang/include/clang/Basic/Diagnostic.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,16 +1435,19 @@ operator<<(const StreamingDiagnostic &DB, T *DC) {
14351435
return DB;
14361436
}
14371437

1438-
// Convert scope enums to their underlying type, so that we don't have
1438+
// Convert scoped enums to their underlying type, so that we don't have
14391439
// clutter the emitting code with `llvm::to_underlying()`.
14401440
// We also need to disable implicit conversion for the first argument,
14411441
// because classes that derive from StreamingDiagnostic define their own
14421442
// templated operator<< that accept a wide variety of types, leading
14431443
// to ambiguity.
1444-
template <typename T, typename U>
1444+
template <typename T, typename U,
1445+
typename UnderlyingU = typename std::enable_if_t<
1446+
std::is_enum_v<std::remove_reference_t<U>>,
1447+
std::underlying_type<std::remove_reference_t<U>>>::type>
14451448
inline std::enable_if_t<
14461449
std::is_same_v<std::remove_const_t<T>, StreamingDiagnostic> &&
1447-
llvm::is_scoped_enum_v<std::remove_reference_t<U>>,
1450+
!std::is_convertible_v<U, UnderlyingU>,
14481451
const StreamingDiagnostic &>
14491452
operator<<(const T &DB, U &&SE) {
14501453
DB << llvm::to_underlying(SE);

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7296,6 +7296,11 @@ def warn_consecutive_comparison : Warning<
72967296
"chained comparison 'X %0 Y %1 Z' does not behave the same as a mathematical expression">,
72977297
InGroup<Parentheses>, DefaultError;
72987298

7299+
def warn_comparison_in_fold_expression : Warning<
7300+
"comparison in fold expression would evaluate to '(X %0 Y) %0 Z' "
7301+
"which does not behave the same as a mathematical expression">,
7302+
InGroup<Parentheses>, DefaultError;
7303+
72997304
def warn_enum_constant_in_bool_context : Warning<
73007305
"converting the enum constant to a boolean">,
73017306
InGroup<IntInBoolContext>, DefaultIgnore;

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7236,13 +7236,15 @@ class Sema final : public SemaBase {
72367236
ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind,
72377237
Expr *LHSExpr, Expr *RHSExpr);
72387238
ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc,
7239-
Expr *LHSExpr, Expr *RHSExpr);
7239+
Expr *LHSExpr, Expr *RHSExpr,
7240+
bool ForFoldExpression = false);
72407241

72417242
/// CreateBuiltinBinOp - Creates a new built-in binary operation with
72427243
/// operator @p Opc at location @c TokLoc. This routine only supports
72437244
/// built-in operations; ActOnBinOp handles overloaded operators.
72447245
ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc,
7245-
Expr *LHSExpr, Expr *RHSExpr);
7246+
Expr *LHSExpr, Expr *RHSExpr,
7247+
bool ForFoldExpression = false);
72467248
void LookupBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc,
72477249
UnresolvedSetImpl &Functions);
72487250

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
519519
return emitBinaryOperatorLValue(cast<BinaryOperator>(e));
520520
case Expr::CompoundAssignOperatorClass: {
521521
QualType ty = e->getType();
522-
if (const AtomicType *at = ty->getAs<AtomicType>()) {
522+
if (ty->getAs<AtomicType>()) {
523523
cgm.errorNYI(e->getSourceRange(),
524524
"CompoundAssignOperator with AtomicType");
525525
return LValue();

clang/lib/CIR/CodeGen/CIRGenStmtOpenACCLoop.cpp

Lines changed: 89 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,103 @@
1313
#include "CIRGenBuilder.h"
1414
#include "CIRGenFunction.h"
1515
#include "CIRGenOpenACCClause.h"
16-
#include "mlir/Dialect/OpenACC/OpenACC.h"
16+
1717
#include "clang/AST/OpenACCClause.h"
1818
#include "clang/AST/StmtOpenACC.h"
1919

20+
#include "mlir/Dialect/OpenACC/OpenACC.h"
21+
2022
using namespace clang;
2123
using namespace clang::CIRGen;
2224
using namespace cir;
2325
using namespace mlir::acc;
2426

2527
mlir::LogicalResult
2628
CIRGenFunction::emitOpenACCLoopConstruct(const OpenACCLoopConstruct &s) {
27-
cgm.errorNYI(s.getSourceRange(), "OpenACC Loop Construct");
28-
return mlir::failure();
29+
mlir::Location start = getLoc(s.getSourceRange().getBegin());
30+
mlir::Location end = getLoc(s.getSourceRange().getEnd());
31+
llvm::SmallVector<mlir::Type> retTy;
32+
llvm::SmallVector<mlir::Value> operands;
33+
auto op = builder.create<LoopOp>(start, retTy, operands);
34+
35+
// TODO(OpenACC): In the future we are going to need to come up with a
36+
// transformation here that can teach the acc.loop how to figure out the
37+
// 'lowerbound', 'upperbound', and 'step'.
38+
//
39+
// -'upperbound' should fortunately be pretty easy as it should be
40+
// in the initialization section of the cir.for loop. In Sema, we limit to
41+
// just the forms 'Var = init', `Type Var = init`, or `Var = init` (where it
42+
// is an operator= call)`. However, as those are all necessary to emit for
43+
// the init section of the for loop, they should be inside the initial
44+
// cir.scope.
45+
//
46+
// -'upperbound' should be somewhat easy to determine. Sema is limiting this
47+
// to: ==, <, >, !=, <=, >= builtin operators, the overloaded 'comparison'
48+
// operations, and member-call expressions.
49+
//
50+
// For the builtin comparison operators, we can pretty well deduce based on
51+
// the comparison what the 'end' object is going to be, and the inclusive
52+
// nature of it.
53+
//
54+
// For the overloaded operators, Sema will ensure that at least one side of
55+
// the operator is the init variable, so we can deduce the comparison there
56+
// too. The standard places no real bounds on WHAT the comparison operators do
57+
// for a `RandomAccessIterator` however, so we'll have to just 'assume' they
58+
// do the right thing? Note that this might be incrementing by a different
59+
// 'object', not an integral, so it isn't really clear to me what we can do to
60+
// determine the other side.
61+
//
62+
// Member-call expressions are the difficult ones. I don't think there is
63+
// anything we can deduce from this to determine the 'end', so we might end up
64+
// having to go back to Sema and make this ill-formed.
65+
//
66+
// HOWEVER: What ACC dialect REALLY cares about is the tripcount, which you
67+
// cannot get (in the case of `RandomAccessIterator`) from JUST 'upperbound'
68+
// and 'lowerbound'. We will likely have to provide a 'recipe' equivalent to
69+
// `std::distance` instead. In the case of integer/pointers, it is fairly
70+
// simple to find: it is just the mathematical subtraction. Howver, in the
71+
// case of `RandomAccessIterator`, we have to enable the use of `operator-`.
72+
// FORTUNATELY the standard requires this to work correctly for
73+
// `RandomAccessIterator`, so we don't have to implement a `std::distance`
74+
// that loops through, like we would for a forward/etc iterator.
75+
//
76+
// 'step': Sema is currently allowing builtin ++,--, +=, -=, *=, /=, and =
77+
// operators. Additionally, it allows the equivalent for the operator-call, as
78+
// well as member-call.
79+
//
80+
// For builtin operators, we perhaps should refine the assignment here. It
81+
// doesn't really help us know the 'step' count at all, but we could perhaps
82+
// do one more step of analysis in Sema to allow something like Var = Var + 1.
83+
// For the others, this should get us the step reasonably well.
84+
//
85+
// For the overloaded operators, we have the same problems as for
86+
// 'upperbound', plus not really knowing what they do. Member-call expressions
87+
// are again difficult, and we might want to reconsider allowing these in
88+
// Sema.
89+
//
90+
91+
// Emit all clauses.
92+
{
93+
mlir::OpBuilder::InsertionGuard guardCase(builder);
94+
// Sets insertion point before the 'op', since every new expression needs to
95+
// be before the operation.
96+
builder.setInsertionPoint(op);
97+
makeClauseEmitter(op, *this, builder, s.getDirectiveKind(),
98+
s.getDirectiveLoc())
99+
.VisitClauseList(s.clauses());
100+
}
101+
102+
mlir::LogicalResult stmtRes = mlir::success();
103+
// Emit body.
104+
{
105+
mlir::Block &block = op.getRegion().emplaceBlock();
106+
mlir::OpBuilder::InsertionGuard guardCase(builder);
107+
builder.setInsertionPointToEnd(&block);
108+
LexicalScope ls{*this, start, builder.getInsertionBlock()};
109+
110+
stmtRes = emitStmt(s.getLoop(), /*useCurrentScope=*/true);
111+
builder.create<mlir::acc::YieldOp>(end);
112+
}
113+
114+
return stmtRes;
29115
}

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,9 @@ class CodeGenFunction : public CodeGenTypeCache {
869869
}
870870
CGM.setAtomicOpts(AO);
871871
}
872+
873+
CGAtomicOptionsRAII(const CGAtomicOptionsRAII &) = delete;
874+
CGAtomicOptionsRAII &operator=(const CGAtomicOptionsRAII &) = delete;
872875
~CGAtomicOptionsRAII() { CGM.setAtomicOpts(SavedAtomicOpts); }
873876

874877
private:

clang/lib/Lex/ModuleMap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1959,7 +1959,7 @@ void ModuleMapLoader::handleExportDecl(const modulemap::ExportDecl &ED) {
19591959
}
19601960

19611961
void ModuleMapLoader::handleExportAsDecl(const modulemap::ExportAsDecl &EAD) {
1962-
auto ModName = EAD.Id.front();
1962+
const auto &ModName = EAD.Id.front();
19631963

19641964
if (!ActiveModule->ExportAsModule.empty()) {
19651965
if (ActiveModule->ExportAsModule == ModName.first) {

clang/lib/Sema/SemaExpr.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15024,8 +15024,8 @@ static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx,
1502415024
}
1502515025

1502615026
ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
15027-
BinaryOperatorKind Opc,
15028-
Expr *LHSExpr, Expr *RHSExpr) {
15027+
BinaryOperatorKind Opc, Expr *LHSExpr,
15028+
Expr *RHSExpr, bool ForFoldExpression) {
1502915029
if (getLangOpts().CPlusPlus11 && isa<InitListExpr>(RHSExpr)) {
1503015030
// The syntax only allows initializer lists on the RHS of assignment,
1503115031
// so we don't need to worry about accepting invalid code for
@@ -15156,7 +15156,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
1515615156
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc);
1515715157

1515815158
if (const auto *BI = dyn_cast<BinaryOperator>(LHSExpr);
15159-
BI && BI->isComparisonOp())
15159+
!ForFoldExpression && BI && BI->isComparisonOp())
1516015160
Diag(OpLoc, diag::warn_consecutive_comparison)
1516115161
<< BI->getOpcodeStr() << BinaryOperator::getOpcodeStr(Opc);
1516215162

@@ -15567,8 +15567,8 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc,
1556715567
}
1556815568

1556915569
ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
15570-
BinaryOperatorKind Opc,
15571-
Expr *LHSExpr, Expr *RHSExpr) {
15570+
BinaryOperatorKind Opc, Expr *LHSExpr,
15571+
Expr *RHSExpr, bool ForFoldExpression) {
1557215572
ExprResult LHS, RHS;
1557315573
std::tie(LHS, RHS) = CorrectDelayedTyposInBinOp(*this, Opc, LHSExpr, RHSExpr);
1557415574
if (!LHS.isUsable() || !RHS.isUsable())
@@ -15642,7 +15642,8 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
1564215642
LHSExpr->getType()->isOverloadableType()))
1564315643
return BuildOverloadedBinOp(*this, S, OpLoc, Opc, LHSExpr, RHSExpr);
1564415644

15645-
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
15645+
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr,
15646+
ForFoldExpression);
1564615647
}
1564715648

1564815649
// Don't resolve overloads if the other type is overloadable.
@@ -15706,7 +15707,7 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc,
1570615707
}
1570715708

1570815709
// Build a built-in binary operation.
15709-
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr);
15710+
return CreateBuiltinBinOp(OpLoc, Opc, LHSExpr, RHSExpr, ForFoldExpression);
1571015711
}
1571115712

1571215713
static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {

clang/lib/Sema/SemaOpenACC.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,7 @@ void SemaOpenACC::ActOnForStmtBegin(SourceLocation ForLoc, const Stmt *First,
15601560
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15611561
const Stmt *OldRangeFor,
15621562
const Stmt *RangeFor) {
1563-
if (!getLangOpts().OpenACC)
1563+
if (!getLangOpts().OpenACC || OldRangeFor == nullptr || RangeFor == nullptr)
15641564
return;
15651565

15661566
ForStmtBeginChecker FSBC{*this, ForLoc,
@@ -1576,7 +1576,7 @@ void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15761576

15771577
void SemaOpenACC::ActOnRangeForStmtBegin(SourceLocation ForLoc,
15781578
const Stmt *RangeFor) {
1579-
if (!getLangOpts().OpenACC)
1579+
if (!getLangOpts().OpenACC || RangeFor == nullptr)
15801580
return;
15811581

15821582
ForStmtBeginChecker FSBC = {*this, ForLoc,

clang/lib/Sema/TreeTransform.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,10 +2975,11 @@ class TreeTransform {
29752975
///
29762976
/// By default, performs semantic analysis to build the new expression.
29772977
/// Subclasses may override this routine to provide different behavior.
2978-
ExprResult RebuildBinaryOperator(SourceLocation OpLoc,
2979-
BinaryOperatorKind Opc,
2980-
Expr *LHS, Expr *RHS) {
2981-
return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS);
2978+
ExprResult RebuildBinaryOperator(SourceLocation OpLoc, BinaryOperatorKind Opc,
2979+
Expr *LHS, Expr *RHS,
2980+
bool ForFoldExpression = false) {
2981+
return getSema().BuildBinOp(/*Scope=*/nullptr, OpLoc, Opc, LHS, RHS,
2982+
ForFoldExpression);
29822983
}
29832984

29842985
/// Build a new rewritten operator expression.
@@ -16518,6 +16519,7 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
1651816519
return true;
1651916520
}
1652016521

16522+
bool WarnedOnComparison = false;
1652116523
for (unsigned I = 0; I != *NumExpansions; ++I) {
1652216524
Sema::ArgPackSubstIndexRAII SubstIndex(
1652316525
getSema(), LeftFold ? I : *NumExpansions - I - 1);
@@ -16545,7 +16547,17 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
1654516547
Functions, LHS, RHS);
1654616548
} else {
1654716549
Result = getDerived().RebuildBinaryOperator(E->getEllipsisLoc(),
16548-
E->getOperator(), LHS, RHS);
16550+
E->getOperator(), LHS, RHS,
16551+
/*ForFoldExpresion=*/true);
16552+
if (!WarnedOnComparison && Result.isUsable()) {
16553+
if (auto *BO = dyn_cast<BinaryOperator>(Result.get());
16554+
BO && BO->isComparisonOp()) {
16555+
WarnedOnComparison = true;
16556+
SemaRef.Diag(BO->getBeginLoc(),
16557+
diag::warn_comparison_in_fold_expression)
16558+
<< BO->getOpcodeStr();
16559+
}
16560+
}
1654916561
}
1655016562
} else
1655116563
Result = Out;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %clang_cc1 -fopenacc -Wno-openacc-self-if-potential-conflict -emit-cir -fclangir %s -o - | FileCheck %s
2+
3+
extern "C" void acc_loop(int *A, int *B, int *C, int N) {
4+
// CHECK: cir.func @acc_loop(%[[ARG_A:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_B:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_C:.*]]: !cir.ptr<!s32i> loc{{.*}}, %[[ARG_N:.*]]: !s32i loc{{.*}}) {
5+
// CHECK-NEXT: %[[ALLOCA_A:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["A", init]
6+
// CHECK-NEXT: %[[ALLOCA_B:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["B", init]
7+
// CHECK-NEXT: %[[ALLOCA_C:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["C", init]
8+
// CHECK-NEXT: %[[ALLOCA_N:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["N", init]
9+
// CHECK-NEXT: cir.store %[[ARG_A]], %[[ALLOCA_A]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
10+
// CHECK-NEXT: cir.store %[[ARG_B]], %[[ALLOCA_B]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
11+
// CHECK-NEXT: cir.store %[[ARG_C]], %[[ALLOCA_C]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
12+
// CHECK-NEXT: cir.store %[[ARG_N]], %[[ALLOCA_N]] : !s32i, !cir.ptr<!s32i>
13+
14+
15+
#pragma acc loop
16+
for (unsigned I = 0u; I < N; ++I) {
17+
A[I] = B[I] + C[I];
18+
}
19+
// CHECK-NEXT: acc.loop {
20+
// CHECK-NEXT: cir.scope {
21+
// CHECK: cir.for : cond {
22+
// CHECK: cir.condition
23+
// CHECK-NEXT: } body {
24+
// CHECK-NEXT: cir.scope {
25+
// CHECK: }
26+
// CHECK-NEXT: cir.yield
27+
// CHECK-NEXT: } step {
28+
// CHECK: cir.yield
29+
// CHECK-NEXT: } loc
30+
// CHECK-NEXT: } loc
31+
// CHECK-NEXT: acc.yield
32+
// CHECK-NEXT: } loc
33+
}

clang/test/CIR/CodeGenOpenACC/openacc-not-implemented.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@ void HelloWorld(int *A, int *B, int *C, int N) {
99
for (unsigned I = 0; I < N; ++I)
1010
A[I] = B[I] + C[I];
1111

12-
// expected-error@+2{{ClangIR code gen Not Yet Implemented: OpenACC Loop Construct}}
13-
// expected-error@+1{{ClangIR code gen Not Yet Implemented: statement}}
14-
#pragma acc loop
15-
for (unsigned I = 0; I < N; ++I)
16-
A[I] = B[I] + C[I];
17-
1812
// expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenACC Declare Construct}}
1913
#pragma acc declare create(A)
2014
}

clang/test/Parser/cxx1z-fold-expressions.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ template<typename ...T> void as_operand_of_cast(int a, T ...t) {
5252

5353
// fold-operator can be '>' or '>>'.
5454
template <int... N> constexpr bool greaterThan() { return (N > ...); }
55+
// expected-error@-1 {{comparison in fold expression}}
56+
5557
template <int... N> constexpr int rightShift() { return (N >> ...); }
5658

57-
static_assert(greaterThan<2, 1>());
59+
static_assert(greaterThan<2, 1>()); // expected-note {{in instantiation}}
5860
static_assert(rightShift<10, 1>() == 5);
5961

6062
template <auto V> constexpr auto Identity = V;

clang/test/SemaTemplate/cxx1z-fold-expressions.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,30 @@ bool f();
132132
template <typename... T>
133133
void g(bool = (f<T>() || ...));
134134
}
135+
136+
137+
namespace comparison_warning {
138+
struct S {
139+
bool operator<(const S&) const;
140+
bool operator<(int) const;
141+
bool operator==(const S&) const;
142+
};
143+
144+
template <typename...T>
145+
void f(T... ts) {
146+
(void)(ts == ...);
147+
// expected-error@-1 2{{comparison in fold expression would evaluate to '(X == Y) == Z'}}
148+
(void)(ts < ...);
149+
// expected-error@-1 2{{comparison in fold expression would evaluate to '(X < Y) < Z'}}
150+
(void)(... < ts);
151+
// expected-error@-1 2{{comparison in fold expression would evaluate to '(X < Y) < Z'}}
152+
}
153+
154+
void test() {
155+
f(0, 1, 2); // expected-note{{in instantiation}}
156+
f(0, 1); // expected-note{{in instantiation}}
157+
f(S{}, S{});
158+
f(0);
159+
}
160+
161+
};

0 commit comments

Comments
 (0)