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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits