]> granicus.if.org Git - clang/commitdiff
Don't produce redundant parentheses warning for "A (::B);" and the like.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 21 Dec 2017 20:50:39 +0000 (20:50 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 21 Dec 2017 20:50:39 +0000 (20:50 +0000)
The parentheses here are not redundant as they affect the binding of the
'::' token.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321304 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaType.cpp
test/Parser/cxx-decl.cpp

index 7a50f542a39a17949122c4fe92574ac565e4b83b..b45d31c6b1e751f044850ef7e7c85f5cb8ce521d 100644 (file)
@@ -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);
index 8a7a38860539206b2fd2667066ffd5cf1dc8a6ed..711a874f6a27f312b2fb7939b080c666899de43e 100644 (file)
@@ -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<int&&>(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}}