cjdb updated this revision to Diff 363927.
cjdb retitled this revision from "[clang] adds warning to alert user when they 
use alternative tokens as references" to "[clang] adds warning to alert user 
when they use alternative tokens in declarations".
cjdb edited the summary of this revision.
cjdb added a comment.

extends functionality to account for destructors, member functions, and block 
pointers


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107292/new/

https://reviews.llvm.org/D107292

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/test/Parser/cxx-decl.cpp
  clang/test/Parser/cxx0x-decl.cpp
  clang/test/Parser/warn-declare-references-with-symbols.cpp

Index: clang/test/Parser/warn-declare-references-with-symbols.cpp
===================================================================
--- /dev/null
+++ clang/test/Parser/warn-declare-references-with-symbols.cpp
@@ -0,0 +1,130 @@
+// RUN: %clang_cc1 -std=c++98 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++98 -fblocks -fsyntax-only -Wdeclare-with-symbols -verify %s
+// RUN: %clang_cc1 -std=c++11 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fblocks -fsyntax-only -Wdeclare-with-symbols -verify %s
+// RUN: %clang_cc1 -std=c++14 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fblocks -fsyntax-only -Wdeclare-with-symbols -verify %s
+// RUN: %clang_cc1 -std=c++20 -fblocks -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fblocks -fsyntax-only -Wdeclare-with-symbols -verify %s
+
+int i = 0;
+
+int bitand lr1 = i; // expected-warning{{use '&' when declaring lvalue references}}
+int &lr2 = i; // no warning
+
+template<class T>
+void f(T bitand); // expected-warning{{use '&' when declaring lvalue references}}
+
+template<class T>
+void f(T &); // no warning
+
+int(xor bp1)(); // expected-warning{{use '^' when declaring block pointers}}
+int(^bp2)();
+
+struct S1 {
+  compl S1(); // expected-warning{{use '~' when declaring destructors}}
+};
+
+struct S2 {
+  ~S2();
+};
+
+S2::compl S2() // expected-warning{{use '~' when declaring destructors}}
+{}
+
+struct S3 {
+  ~S3(); // no warning
+};
+
+struct S4 {
+  ~S4();
+};
+
+S4::~S4() // no warning
+{}
+
+#if __cplusplus >= 201103L
+int and rr1 = 0; // expected-warning{{use '&&' when declaring rvalue references}}
+int &&rr2 = 0; // no warning
+
+using bad_block_ptr = int(xor)(); // expected-warning{{use '^' when declaring block pointers}}
+using good_block_ptr = int(^)();
+
+using bad_lr = int bitand; // expected-warning{{use '&' when declaring lvalue references}}
+using good_lr = int &; // no warning
+
+using bad_rr = int and; // expected-warning{{use '&&' when declaring rvalue references}}
+using good_rr = int &&; // no warning
+
+auto and fr1 = i; // expected-warning{{use '&&' when declaring rvalue references}}
+auto &&fr2 = i; // no warning
+
+auto and fr3 = 0; // expected-warning{{use '&&' when declaring rvalue references}}
+auto &&fr4 = 0; // no warning
+
+template<class T>
+void f(T and); // expected-warning{{use '&&' when declaring rvalue references}}
+
+template<class T>
+void f(T &&); // no warning
+
+struct S5 {
+  void f() bitand;
+  // expected-warning@-1{{use '&' when declaring lvalue ref-qualified member functions}}
+  void f() const bitand;
+  // expected-warning@-1{{use '&' when declaring lvalue ref-qualified member functions}}
+  void f() volatile bitand;
+  // expected-warning@-1{{use '&' when declaring lvalue ref-qualified member functions}}
+  void f() const volatile bitand;
+  // expected-warning@-1{{use '&' when declaring lvalue ref-qualified member functions}}
+  void f() and;
+  // expected-warning@-1{{use '&&' when declaring rvalue ref-qualified member functions}}
+  void f() const and;
+  // expected-warning@-1{{use '&&' when declaring rvalue ref-qualified member functions}}
+  void f() volatile and;
+  // expected-warning@-1{{use '&&' when declaring rvalue ref-qualified member functions}}
+  void f() const volatile and;
+  // expected-warning@-1{{use '&&' when declaring rvalue ref-qualified member functions}}
+};
+
+struct S6 {
+  void f() &; // no warning
+  void f() const &; // no warning
+  void f() volatile &; // no warning
+  void f() const volatile &; // no warning
+  void f() &&; // no warning
+  void f() const &&; // no warning
+  void f() volatile &&; // no warning
+  void f() const volatile &&; // no warning
+};
+#endif // __cplusplus > 201103L
+
+#if __cplusplus >= 201402L
+template<class T>
+T bitand lr3 = i; // expected-warning{{use '&' when declaring lvalue references}}
+
+template<class T>
+T &lr4 = i; // no warning
+
+template<class T>
+T and rr3 = i; // expected-warning{{use '&&' when declaring rvalue references}}
+
+template<class T>
+T &&rr4 = i; // no warning
+#endif // __cplusplus >= 201402L
+
+#if __cplusplus >= 202002L
+template<class T>
+concept C1 = requires(T bitand x) { x; };
+// expected-warning@-1{{use '&' when declaring lvalue references}}
+
+template<class T>
+concept C2 = requires(T &x) { x; }; // no warning
+
+template<class T>
+concept C3 = requires(T and x) { x; };
+// expected-warning@-1{{use '&&' when declaring rvalue references}}
+
+template<class T>
+concept C4 = requires(T &&x) { x; }; // no warning
+#endif // __cplusplus >= 202002L
Index: clang/test/Parser/cxx0x-decl.cpp
===================================================================
--- clang/test/Parser/cxx0x-decl.cpp
+++ clang/test/Parser/cxx0x-decl.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -fsyntax-only -std=c++2a -pedantic-errors -triple x86_64-linux-gnu %s
+// RUN: %clang_cc1 -verify -fsyntax-only -std=c++2a -Wno-declare-with-symbols -pedantic-errors -triple x86_64-linux-gnu %s
 
 // Make sure we know these are legitimate commas and not typos for ';'.
 namespace Commas {
Index: clang/test/Parser/cxx-decl.cpp
===================================================================
--- clang/test/Parser/cxx-decl.cpp
+++ clang/test/Parser/cxx-decl.cpp
@@ -1,6 +1,6 @@
-// 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
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -Wno-declare-with-symbols -pedantic-errors -fcxx-exceptions -fexceptions %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -Wno-declare-with-symbols -pedantic-errors -fcxx-exceptions -fexceptions -std=c++98 %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -Wno-declare-with-symbols -pedantic-errors -fcxx-exceptions -fexceptions -std=c++11 %s
 
 const char const *x10; // expected-error {{duplicate 'const' declaration specifier}}
 
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1728,6 +1728,16 @@
 
   // Parse the tilde.
   assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
+
+  if (*PP.getSourceManager().getCharacterData(Tok.getLocation()) != '~') {
+    constexpr int Tilde = 2;
+    constexpr int Empty = 2;
+    constexpr int Destructors = 1;
+    Diag(Tok.getLocation(), diag::warn_declare_with_symbols)
+        << Tilde << Empty << Destructors
+        << FixItHint::CreateReplacement(Tok.getLocation(), "~");
+  }
+
   SourceLocation TildeLoc = ConsumeToken();
 
   if (Tok.is(tok::kw_decltype) && !FirstTypeName.isValid()) {
@@ -2917,6 +2927,16 @@
     //    unary complement rather than treating ~X as referring to a destructor.
 
     // Parse the '~'.
+
+    if (*PP.getSourceManager().getCharacterData(Tok.getLocation()) != '~') {
+      constexpr int Tilde = 2;
+      constexpr int Empty = 2;
+      constexpr int Destructors = 1;
+      Diag(Tok.getLocation(), diag::warn_declare_with_symbols)
+          << Tilde << Empty << Destructors
+          << FixItHint::CreateReplacement(Tok.getLocation(), "~");
+    }
+
     SourceLocation TildeLoc = ConsumeToken();
 
     if (TemplateSpecified) {
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -10,16 +10,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Parse/Parser.h"
-#include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/PrettyDeclStackTrace.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/Attributes.h"
 #include "clang/Basic/CharInfo.h"
+#include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Parse/ParseDiagnostic.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/RAIIObjectsForParser.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
@@ -5800,6 +5801,8 @@
   SourceLocation Loc = ConsumeToken();  // Eat the *, ^, & or &&.
   D.SetRangeEnd(Loc);
 
+  const SourceManager &SM = PP.getSourceManager();
+
   if (Kind == tok::star || Kind == tok::caret) {
     // Is a pointer.
     DeclSpec DS(AttrFactory);
@@ -5822,22 +5825,47 @@
                         DS.getVolatileSpecLoc(), DS.getRestrictSpecLoc(),
                         DS.getAtomicSpecLoc(), DS.getUnalignedSpecLoc()),
                     std::move(DS.getAttributes()), SourceLocation());
-    else
+    else {
+      if (*SM.getCharacterData(Loc) != '^') {
+        constexpr int Caret = 3;
+        constexpr int Empty = 2;
+        constexpr int BlockPointers = 2;
+        Diag(Loc, diag::warn_declare_with_symbols)
+            << Caret << Empty << BlockPointers
+            << FixItHint::CreateReplacement(Loc, "^");
+      }
+
       // Remember that we parsed a Block type, and remember the type-quals.
       D.AddTypeInfo(
           DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), Loc),
           std::move(DS.getAttributes()), SourceLocation());
+    }
   } else {
     // Is a reference
     DeclSpec DS(AttrFactory);
 
-    // Complain about rvalue references in C++03, but then go on and build
-    // the declarator.
-    if (Kind == tok::ampamp)
+    constexpr int References = 0;
+    if (Kind == tok::amp && *SM.getCharacterData(Loc) != '&') {
+      constexpr int Lvalue = 0;
+      Diag(Loc, diag::warn_declare_with_symbols)
+          << Lvalue << Lvalue << References
+          << FixItHint::CreateReplacement(Loc, "&");
+    }
+    if (Kind == tok::ampamp) {
+      // Complain about rvalue references in C++03, but then go on and build
+      // the declarator.
       Diag(Loc, getLangOpts().CPlusPlus11 ?
            diag::warn_cxx98_compat_rvalue_reference :
            diag::ext_rvalue_reference);
 
+      if (*SM.getCharacterData(Loc) != '&') {
+        constexpr int Rvalue = 1;
+        Diag(Loc, diag::warn_declare_with_symbols)
+            << Rvalue << Rvalue << References
+            << FixItHint::CreateReplacement(Loc, "&&");
+      }
+    }
+
     // GNU-style and C++11 attributes are allowed here, as is restrict.
     ParseTypeQualifierListOpt(DS);
     D.ExtendWithDeclSpec(DS);
@@ -6688,6 +6716,16 @@
 
     RefQualifierIsLValueRef = Tok.is(tok::amp);
     RefQualifierLoc = ConsumeToken();
+
+    if (*PP.getSourceManager().getCharacterData(RefQualifierLoc) != '&') {
+      int Qualifier = RefQualifierIsLValueRef ? 0 : 1;
+      constexpr int RefQualifiedMemberFunc = 3;
+      Diag(Tok.getLocation(), diag::warn_declare_with_symbols)
+          << Qualifier << Qualifier << RefQualifiedMemberFunc
+          << FixItHint::CreateReplacement(Tok.getLocation(),
+                                          RefQualifierIsLValueRef ? "&" : "&&");
+    }
+
     return true;
   }
   return false;
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1547,4 +1547,9 @@
 
 def note_max_tokens_total_override : Note<"total token limit set here">;
 
+def warn_declare_with_symbols : Warning<
+  "use '%select{&|&&|~|^}0' when declaring%select{ lvalue| rvalue|}1 "
+  "%select{references|destructors|block pointers|ref-qualified member functions}2">,
+  InGroup<DiagGroup<"declare-with-symbols">>;
+
 } // end of Parser diagnostics
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to