Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 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
15 changes: 14 additions & 1 deletion clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -2171,10 +2171,15 @@ class ParenExpr : public Expr {
SourceLocation L, R;
Stmt *Val;
public:
enum TransformConstraint : uint8_t {
None = 0, // No specific preservation required
Preserve = 1, // Parentheses have always to be preserved
};

ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
: Expr(ParenExprClass, val->getType(), val->getValueKind(),
val->getObjectKind()),
L(l), R(r), Val(val) {
L(l), R(r), Val(val), TC(TransformConstraint::None) {
setDependence(computeDependence(this));
}

Expand Down Expand Up @@ -2206,6 +2211,14 @@ class ParenExpr : public Expr {
const_child_range children() const {
return const_child_range(&Val, &Val + 1);
}

TransformConstraint getTransformConstraint() const { return TC; }
void setTransformConstraint(TransformConstraint Constraint) {
TC = Constraint;
}

private:
TransformConstraint TC;
};

/// UnaryOperator - This represents the unary-expression's (except sizeof and
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20220,7 +20220,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
if (parenLoc.isInvalid() || parenLoc.isMacroID())
return;
// Don't warn for dependent expressions.
if (ParenE->isTypeDependent())
if (ParenE->isTypeDependent() ||
ParenE->getTransformConstraint() == ParenExpr::Preserve)
return;

Expr *E = ParenE->IgnoreParens();
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -15661,12 +15661,16 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) {
return true;
}

if (*NumExpansions == 1) {
if (ParenExpr *PE = dyn_cast<ParenExpr>(Result.get()))
PE->setTransformConstraint(ParenExpr::Preserve);
}

// 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
40 changes: 39 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,41 @@ 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 test() {
t1(0, 1);
t2<>();
t3(1, 2, 3);
t3(0, 1);
t4(0, 1);
t5(0, 1);
t6(0, 0);
}
}