Author: Oleksandr T. Date: 2024-10-07T20:14:46+02:00 New Revision: 41b09c5346324fc0fd2642f3df216a246f9fb98b
URL: https://github.com/llvm/llvm-project/commit/41b09c5346324fc0fd2642f3df216a246f9fb98b DIFF: https://github.com/llvm/llvm-project/commit/41b09c5346324fc0fd2642f3df216a246f9fb98b.diff LOG: [Clang] omit parentheses in fold expressions with a single expansion (#110761) Fixes #101863 Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/AST/Expr.h clang/include/clang/AST/Stmt.h clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/TreeTransform.h clang/lib/Serialization/ASTReaderStmt.cpp clang/lib/Serialization/ASTWriterStmt.cpp clang/test/SemaCXX/warn-assignment-condition.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3d03766d55a8aa..9762db9209b79a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -378,6 +378,8 @@ Improvements to Clang's diagnostics - Clang now emits a diagnostic note at the class declaration when the method definition does not match any declaration (#GH110638). +- Clang now omits warnings for extra parentheses in fold expressions with single expansion (#GH101863). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 57353855c51e7c..607bf313c4d95e 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -2170,11 +2170,13 @@ class SYCLUniqueStableNameExpr final : public Expr { class ParenExpr : public Expr { SourceLocation L, R; Stmt *Val; + public: ParenExpr(SourceLocation l, SourceLocation r, Expr *val) : Expr(ParenExprClass, val->getType(), val->getValueKind(), val->getObjectKind()), L(l), R(r), Val(val) { + ParenExprBits.ProducedByFoldExpansion = false; setDependence(computeDependence(this)); } @@ -2206,6 +2208,13 @@ class ParenExpr : public Expr { const_child_range children() const { return const_child_range(&Val, &Val + 1); } + + bool isProducedByFoldExpansion() const { + return ParenExprBits.ProducedByFoldExpansion != 0; + } + void setIsProducedByFoldExpansion(bool ProducedByFoldExpansion = true) { + ParenExprBits.ProducedByFoldExpansion = ProducedByFoldExpansion; + } }; /// UnaryOperator - This represents the unary-expression's (except sizeof and diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 7aed83e9c68bb7..83fafbabb1d460 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -719,6 +719,18 @@ class alignas(void *) Stmt { unsigned Kind : 3; }; + class ParenExprBitfields { + friend class ASTStmtReader; + friend class ASTStmtWriter; + friend class ParenExpr; + + LLVM_PREFERRED_TYPE(ExprBitfields) + unsigned : NumExprBits; + + LLVM_PREFERRED_TYPE(bool) + unsigned ProducedByFoldExpansion : 1; + }; + class StmtExprBitfields { friend class ASTStmtReader; friend class StmtExpr; @@ -1241,6 +1253,7 @@ class alignas(void *) Stmt { GenericSelectionExprBitfields GenericSelectionExprBits; PseudoObjectExprBitfields PseudoObjectExprBits; SourceLocExprBitfields SourceLocExprBits; + ParenExprBitfields ParenExprBits; // GNU Extensions. StmtExprBitfields StmtExprBits; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 959f0739f03fb9..f930a21ea870ec 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -20223,6 +20223,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { return; Expr *E = ParenE->IgnoreParens(); + if (ParenE->isProducedByFoldExpansion() && ParenE->getSubExpr() == E) + return; if (BinaryOperator *opE = dyn_cast<BinaryOperator>(E)) if (opE->getOpcode() == BO_EQ && diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index ed9412c93c62b3..01c086a602dd5a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -15661,12 +15661,14 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { return true; } + if (ParenExpr *PE = dyn_cast_or_null<ParenExpr>(Result.get())) + PE->setIsProducedByFoldExpansion(); + // If we had no init and an empty pack, and we're not retaining an expansion, // then produce a fallback value or error. if (Result.isUnset()) return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(), E->getOperator()); - return Result; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 2038fe7829af9b..6aaafb2e8d71cc 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -706,6 +706,7 @@ void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { void ASTStmtReader::VisitParenExpr(ParenExpr *E) { VisitExpr(E); + E->setIsProducedByFoldExpansion(Record.readInt()); E->setLParen(readSourceLocation()); E->setRParen(readSourceLocation()); E->setSubExpr(Record.readSubExpr()); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 64e4894dc29fb7..321e0031661ee2 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -786,6 +786,7 @@ void ASTStmtWriter::VisitCharacterLiteral(CharacterLiteral *E) { void ASTStmtWriter::VisitParenExpr(ParenExpr *E) { VisitExpr(E); + Record.push_back(E->isProducedByFoldExpansion()); Record.AddSourceLocation(E->getLParen()); Record.AddSourceLocation(E->getRParen()); Record.AddStmt(E->getSubExpr()); diff --git a/clang/test/SemaCXX/warn-assignment-condition.cpp b/clang/test/SemaCXX/warn-assignment-condition.cpp index 09084e36bb4916..65332846bd0911 100644 --- a/clang/test/SemaCXX/warn-assignment-condition.cpp +++ b/clang/test/SemaCXX/warn-assignment-condition.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wparentheses -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wparentheses -std=c++2a -verify %s struct A { int foo(); @@ -144,3 +144,48 @@ void test() { f(S()); // expected-note {{in instantiation}} } } + +namespace GH101863 { +void t1(auto... args) { + if (((args == 0) or ...)) { } +} + +template <typename... Args> +void t2(Args... args) { + if (((args == 0) or ...)) { } +} + +void t3(auto... args) { + if ((... && (args == 0))) { } +} + +void t4(auto... a, auto... b) { + if (((a == 0) or ...) && ((b == 0) or ...)) { } +} + +void t5(auto... args) { + if ((((args == 0) or ...))) { } +} + +void t6(auto a, auto... b) { + static_assert(__is_same_as(decltype((a)), int&)); + static_assert(__is_same_as(decltype(((b), ...)), int&)); +}; + +void t7(auto... args) { + if ((((args == 0)) or ...)) { } // expected-warning {{equality comparison with extraneous parentheses}} \ + // expected-note {{use '=' to turn this equality comparison into an assignment}} \ + // expected-note {{remove extraneous parentheses around the comparison to silence this warning}} +} + +void test() { + t1(0, 1); + t2<>(); + t3(1, 2, 3); + t3(0, 1); + t4(0, 1); + t5(0, 1); + t6(0, 0); + t7(0); // expected-note {{in instantiation of function template specialization 'GH101863::t7<int>' requested here}} +} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits