diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7a50f542a39a..b45d31c6b1e7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3137,10 +3137,14 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { (T->isRecordType() || T->isDependentType()) && D.getDeclSpec().getTypeQualifiers() == 0 && D.isFirstDeclarator(); + bool StartsWithDeclaratorId = true; for (auto &C : D.type_objects()) { switch (C.Kind) { - case DeclaratorChunk::Pointer: case DeclaratorChunk::Paren: + if (&C == &Paren) + continue; + case DeclaratorChunk::Pointer: + StartsWithDeclaratorId = false; continue; case DeclaratorChunk::Array: @@ -3154,6 +3158,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { // We assume that something like 'T (&x) = y;' is highly likely to not // be intended to be a temporary object. CouldBeTemporaryObject = false; + StartsWithDeclaratorId = false; continue; case DeclaratorChunk::Function: @@ -3166,6 +3171,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { case DeclaratorChunk::Pipe: // These cannot appear in expressions. CouldBeTemporaryObject = false; + StartsWithDeclaratorId = false; continue; } } @@ -3186,6 +3192,18 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { SourceRange ParenRange(Paren.Loc, Paren.EndLoc); if (!CouldBeTemporaryObject) { + // If we have A (::B), the parentheses affect the meaning of the program. + // Suppress the warning in that case. Don't bother looking at the DeclSpec + // here: even (e.g.) "int ::x" is visually ambiguous even though it's + // formally unambiguous. + if (StartsWithDeclaratorId && D.getCXXScopeSpec().isValid()) { + for (NestedNameSpecifier *NNS = D.getCXXScopeSpec().getScopeRep(); NNS; + NNS = NNS->getPrefix()) { + if (NNS->getKind() == NestedNameSpecifier::Global) + return; + } + } + S.Diag(Paren.Loc, diag::warn_redundant_parens_around_declarator) << ParenRange << FixItHint::CreateRemoval(Paren.Loc) << FixItHint::CreateRemoval(Paren.EndLoc); diff --git a/clang/test/Parser/cxx-decl.cpp b/clang/test/Parser/cxx-decl.cpp index 8a7a38860539..711a874f6a27 100644 --- a/clang/test/Parser/cxx-decl.cpp +++ b/clang/test/Parser/cxx-decl.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic-errors -fcxx-exceptions -fexceptions %s -// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic-errors -fcxx-exceptions -fexceptions -std=c++98 %s -// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -pedantic-errors -fcxx-exceptions -fexceptions -std=c++11 %s +// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -pedantic-errors -fcxx-exceptions -fexceptions %s +// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -pedantic-errors -fcxx-exceptions -fexceptions -std=c++98 %s +// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -pedantic-errors -fcxx-exceptions -fexceptions -std=c++11 %s const char const *x10; // expected-error {{duplicate 'const' declaration specifier}} @@ -83,7 +83,7 @@ namespace Commas { int global1, __attribute__(()) global2, - (global5), + (global5), // expected-warning {{redundant parentheses surrounding declarator}} *global6, &global7 = global1, &&global8 = static_cast(global1), @@ -263,6 +263,25 @@ namespace DuplicateFriend { }; } +namespace NNS { + struct A {}; + namespace B { extern A C1, C2, *C3, C4[], C5; } + // Do not produce a redundant parentheses warning here; removing these parens + // changes the meaning of the program. + A (::NNS::B::C1); + A (NNS::B::C2); // expected-warning {{redundant parentheses surrounding declarator}} + A (*::NNS::B::C3); // expected-warning {{redundant parentheses surrounding declarator}} + A (::NNS::B::C4[2]); + // Removing one of these sets of parentheses would be reasonable. + A ((::NNS::B::C5)); // expected-warning {{redundant parentheses surrounding declarator}} + + void f() { + // FIXME: A vexing-parse warning here would be useful. + A(::NNS::B::C1); // expected-error {{definition or redeclaration}} + A(NNS::B::C1); // expected-warning {{redundant paren}} expected-error {{definition or redeclaration}} + } +} + // PR8380 extern "" // expected-error {{unknown linkage language}} test6a { ;// expected-error {{C++ requires a type specifier for all declarations}}