cjdb created this revision.
cjdb added a reviewer: aaron.ballman.
cjdb requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Although the alternative tokens `bitand` and `and` _can_ respectively be
used in place of `&` and `&&` for declarations, this is arguably misuse
of the tokens in contemporary programming. As of this commit, Clang will
warn—by default—when a programmer attempts to declare a name using
alternative tokens in place of reference symbols.

Depends on D107291 <https://reviews.llvm.org/D107291>.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D107292

Files:
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/lib/Parse/ParseDecl.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,63 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wdeclare-references-with-symbols -verify %s
+
+int i = 0;
+
+int bitand lr1 = i; // expected-warning{{use '&' when declaring lvalue references}}
+int &lr2 = i; // no warning
+
+using bad_lr = int bitand; // expected-warning{{use '&' when declaring lvalue references}}
+using good_lr = int &; // no warning
+
+template<class T>
+void f(T bitand); // expected-warning{{use '&' when declaring lvalue references}}
+
+template<class T>
+void f(T &); // no warning
+
+// C++11
+int and rr1 = 0; // expected-warning{{use '&&' when declaring rvalue and forwarding references}}
+int &&rr2 = 0; // no warning
+
+using bad_rr = int and; // expected-warning{{use '&&' when declaring rvalue and forwarding references}}
+using good_rr = int &&; // no warning
+
+auto and fr1 = i; // expected-warning{{use '&&' when declaring rvalue and forwarding references}}
+auto &&fr2 = i; // no warning
+
+auto and fr3 = 0; // expected-warning{{use '&&' when declaring rvalue and forwarding references}}
+auto &&fr4 = 0; // no warning
+
+template<class T>
+void f(T and); // expected-warning{{use '&&' when declaring rvalue and forwarding references}}
+
+template<class T>
+void f(T &&); // no warning
+
+// C++14
+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 and forwarding references}}
+
+template<class T>
+T &&rr4 = i; // no warning
+
+// C++20
+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 and forwarding references}}
+
+template<class T>
+concept C4 = requires(T &&x) { x; }; // no warning
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-references-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-references-with-symbols -pedantic-errors -fcxx-exceptions -fexceptions %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -Wno-declare-references-with-symbols -pedantic-errors -fcxx-exceptions -fexceptions -std=c++98 %s
+// RUN: %clang_cc1 -verify -fsyntax-only -triple i386-linux -Wredundant-parens -Wno-declare-references-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/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -5797,6 +5797,7 @@
 
   // Otherwise, '*' -> pointer, '^' -> block, '&' -> lvalue reference,
   // '&&' -> rvalue reference
+  Token PrevToken = Tok;
   SourceLocation Loc = ConsumeToken();  // Eat the *, ^, & or &&.
   D.SetRangeEnd(Loc);
 
@@ -5831,13 +5832,24 @@
     // 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)
+    if (Kind == tok::amp && PrevToken.getSpelling() != "&") {
+      constexpr int Lvalue = 0;
+      Diag(Loc, diag::warn_declare_references_with_symbols) << Lvalue << Lvalue;
+    }
+    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 (PrevToken.getSpelling() != "&&") {
+        constexpr int AmpAmp = 1;
+        Diag(Loc, diag::warn_declare_references_with_symbols)
+            << AmpAmp << AmpAmp;
+      }
+    }
+
     // GNU-style and C++11 attributes are allowed here, as is restrict.
     ParseTypeQualifierListOpt(DS);
     D.ExtendWithDeclSpec(DS);
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1547,4 +1547,8 @@
 
 def note_max_tokens_total_override : Note<"total token limit set here">;
 
+def warn_declare_references_with_symbols : Warning<
+  "use '%select{&|&&}0' when declaring %select{lvalue|rvalue and forwarding}1 references">,
+  InGroup<DiagGroup<"declare-references-with-symbols">>, DefaultWarn;
+
 } // 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