Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
----------------------------------

Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/AST/Stmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1241,6 +1253,7 @@ class alignas(void *) Stmt {
GenericSelectionExprBitfields GenericSelectionExprBits;
PseudoObjectExprBitfields PseudoObjectExprBits;
SourceLocExprBitfields SourceLocExprBits;
ParenExprBitfields ParenExprBits;

// GNU Extensions.
StmtExprBitfields StmtExprBits;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20224,6 +20224,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 &&
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTReaderStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTWriterStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
47 changes: 46 additions & 1 deletion clang/test/SemaCXX/warn-assignment-condition.cpp
Original file line number Diff line number Diff line change
@@ -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();
Expand Down Expand Up @@ -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}}
}
}