Skip to content

Commit 41b09c5

Browse files
authored
[Clang] omit parentheses in fold expressions with a single expansion (#110761)
Fixes #101863
1 parent d8a656f commit 41b09c5

File tree

8 files changed

+77
-2
lines changed

8 files changed

+77
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ Improvements to Clang's diagnostics
378378

379379
- Clang now emits a diagnostic note at the class declaration when the method definition does not match any declaration (#GH110638).
380380

381+
- Clang now omits warnings for extra parentheses in fold expressions with single expansion (#GH101863).
382+
381383
Improvements to Clang's time-trace
382384
----------------------------------
383385

clang/include/clang/AST/Expr.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2170,11 +2170,13 @@ class SYCLUniqueStableNameExpr final : public Expr {
21702170
class ParenExpr : public Expr {
21712171
SourceLocation L, R;
21722172
Stmt *Val;
2173+
21732174
public:
21742175
ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
21752176
: Expr(ParenExprClass, val->getType(), val->getValueKind(),
21762177
val->getObjectKind()),
21772178
L(l), R(r), Val(val) {
2179+
ParenExprBits.ProducedByFoldExpansion = false;
21782180
setDependence(computeDependence(this));
21792181
}
21802182

@@ -2206,6 +2208,13 @@ class ParenExpr : public Expr {
22062208
const_child_range children() const {
22072209
return const_child_range(&Val, &Val + 1);
22082210
}
2211+
2212+
bool isProducedByFoldExpansion() const {
2213+
return ParenExprBits.ProducedByFoldExpansion != 0;
2214+
}
2215+
void setIsProducedByFoldExpansion(bool ProducedByFoldExpansion = true) {
2216+
ParenExprBits.ProducedByFoldExpansion = ProducedByFoldExpansion;
2217+
}
22092218
};
22102219

22112220
/// UnaryOperator - This represents the unary-expression's (except sizeof and

clang/include/clang/AST/Stmt.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,18 @@ class alignas(void *) Stmt {
719719
unsigned Kind : 3;
720720
};
721721

722+
class ParenExprBitfields {
723+
friend class ASTStmtReader;
724+
friend class ASTStmtWriter;
725+
friend class ParenExpr;
726+
727+
LLVM_PREFERRED_TYPE(ExprBitfields)
728+
unsigned : NumExprBits;
729+
730+
LLVM_PREFERRED_TYPE(bool)
731+
unsigned ProducedByFoldExpansion : 1;
732+
};
733+
722734
class StmtExprBitfields {
723735
friend class ASTStmtReader;
724736
friend class StmtExpr;
@@ -1241,6 +1253,7 @@ class alignas(void *) Stmt {
12411253
GenericSelectionExprBitfields GenericSelectionExprBits;
12421254
PseudoObjectExprBitfields PseudoObjectExprBits;
12431255
SourceLocExprBitfields SourceLocExprBits;
1256+
ParenExprBitfields ParenExprBits;
12441257

12451258
// GNU Extensions.
12461259
StmtExprBitfields StmtExprBits;

clang/lib/Sema/SemaExpr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20223,6 +20223,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
2022320223
return;
2022420224

2022520225
Expr *E = ParenE->IgnoreParens();
20226+
if (ParenE->isProducedByFoldExpansion() && ParenE->getSubExpr() == E)
20227+
return;
2022620228

2022720229
if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E))
2022820230
if (opE->getOpcode() == BO_EQ &&

clang/lib/Sema/TreeTransform.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15661,12 +15661,14 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
1566115661
return true;
1566215662
}
1566315663

15664+
if (ParenExpr *PE = dyn_cast_or_null<ParenExpr>(Result.get()))
15665+
PE->setIsProducedByFoldExpansion();
15666+
1566415667
// If we had no init and an empty pack, and we're not retaining an expansion,
1566515668
// then produce a fallback value or error.
1566615669
if (Result.isUnset())
1566715670
return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(),
1566815671
E->getOperator());
15669-
1567015672
return Result;
1567115673
}
1567215674

clang/lib/Serialization/ASTReaderStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) {
706706

707707
void ASTStmtReader::VisitParenExpr(ParenExpr *E) {
708708
VisitExpr(E);
709+
E->setIsProducedByFoldExpansion(Record.readInt());
709710
E->setLParen(readSourceLocation());
710711
E->setRParen(readSourceLocation());
711712
E->setSubExpr(Record.readSubExpr());

clang/lib/Serialization/ASTWriterStmt.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) {
786786

787787
void ASTStmtWriter::VisitParenExpr(ParenExpr *E) {
788788
VisitExpr(E);
789+
Record.push_back(E->isProducedByFoldExpansion());
789790
Record.AddSourceLocation(E->getLParen());
790791
Record.AddSourceLocation(E->getRParen());
791792
Record.AddStmt(E->getSubExpr());

clang/test/SemaCXX/warn-assignment-condition.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -fsyntax-only -Wparentheses -verify %s
1+
// RUN: %clang_cc1 -fsyntax-only -Wparentheses -std=c++2a -verify %s
22

33
struct A {
44
int foo();
@@ -144,3 +144,48 @@ void test() {
144144
f(S()); // expected-note {{in instantiation}}
145145
}
146146
}
147+
148+
namespace GH101863 {
149+
void t1(auto... args) {
150+
if (((args == 0) or ...)) { }
151+
}
152+
153+
template <typename... Args>
154+
void t2(Args... args) {
155+
if (((args == 0) or ...)) { }
156+
}
157+
158+
void t3(auto... args) {
159+
if ((... && (args == 0))) { }
160+
}
161+
162+
void t4(auto... a, auto... b) {
163+
if (((a == 0) or ...) && ((b == 0) or ...)) { }
164+
}
165+
166+
void t5(auto... args) {
167+
if ((((args == 0) or ...))) { }
168+
}
169+
170+
void t6(auto a, auto... b) {
171+
static_assert(__is_same_as(decltype((a)), int&));
172+
static_assert(__is_same_as(decltype(((b), ...)), int&));
173+
};
174+
175+
void t7(auto... args) {
176+
if ((((args == 0)) or ...)) { } // expected-warning {{equality comparison with extraneous parentheses}} \
177+
// expected-note {{use '=' to turn this equality comparison into an assignment}} \
178+
// expected-note {{remove extraneous parentheses around the comparison to silence this warning}}
179+
}
180+
181+
void test() {
182+
t1(0, 1);
183+
t2<>();
184+
t3(1, 2, 3);
185+
t3(0, 1);
186+
t4(0, 1);
187+
t5(0, 1);
188+
t6(0, 0);
189+
t7(0); // expected-note {{in instantiation of function template specialization 'GH101863::t7<int>' requested here}}
190+
}
191+
}

0 commit comments

Comments
 (0)