Add a -Wc++0x-compat warning for C++11 keywords used as identifiers when in

C++98 mode. Only the first occurrence of each keyword will produce a warning.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141700 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith 2011-10-11 19:57:52 +00:00
Родитель 2492c89882
Коммит 98d86b98b3
7 изменённых файлов: 78 добавлений и 13 удалений

Просмотреть файл

@ -46,6 +46,9 @@ def charize_microsoft_ext : Extension<"@# is a microsoft extension">;
def ext_token_used : Extension<"extension used">,
InGroup<DiagGroup<"language-extension-token">>;
def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">,
InGroup<CXX0xCompat>;
def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">;
def warn_unterminated_char : ExtWarn<"missing terminating ' character">;
def err_empty_character : Error<"empty character constant">;

Просмотреть файл

@ -58,6 +58,7 @@ class IdentifierInfo {
unsigned ObjCOrBuiltinID :11;
bool HasMacro : 1; // True if there is a #define for this.
bool IsExtension : 1; // True if identifier is a lang extension.
bool IsCXX11CompatKeyword : 1; // True if identifier is a keyword in C++11.
bool IsPoisoned : 1; // True if identifier is poisoned.
bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword.
bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier".
@ -199,6 +200,19 @@ public:
RecomputeNeedsHandleIdentifier();
}
/// is/setIsCXX11CompatKeyword - Initialize information about whether or not
/// this language token is a keyword in C++11. This controls compatibility
/// warnings, and is only true when not parsing C++11. Once a compatibility
/// problem has been diagnosed with this keyword, the flag will be cleared.
bool isCXX11CompatKeyword() const { return IsCXX11CompatKeyword; }
void setIsCXX11CompatKeyword(bool Val) {
IsCXX11CompatKeyword = Val;
if (Val)
NeedsHandleIdentifier = 1;
else
RecomputeNeedsHandleIdentifier();
}
/// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the
/// Preprocessor will emit an error every time this token is used.
void setIsPoisoned(bool Value = true) {
@ -252,7 +266,8 @@ private:
void RecomputeNeedsHandleIdentifier() {
NeedsHandleIdentifier =
(isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() |
isExtensionToken() || (getTokenID() == tok::kw___import_module__));
isExtensionToken() | isCXX11CompatKeyword() ||
(getTokenID() == tok::kw___import_module__));
}
};

Просмотреть файл

@ -752,11 +752,11 @@ public:
/// Diag - Forwarding function for diagnostics. This emits a diagnostic at
/// the specified Token's location, translating the token's start
/// position in the current buffer into a SourcePosition object for rendering.
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) {
DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const {
return Diags->Report(Loc, DiagID);
}
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) {
DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const {
return Diags->Report(Tok.getLocation(), DiagID);
}

Просмотреть файл

@ -32,6 +32,7 @@ IdentifierInfo::IdentifierInfo() {
ObjCOrBuiltinID = 0;
HasMacro = false;
IsExtension = false;
IsCXX11CompatKeyword = false;
IsPoisoned = false;
IsCPPOperatorKeyword = false;
NeedsHandleIdentifier = false;
@ -102,10 +103,10 @@ namespace {
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
///
/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be
/// enabled in the specified langauge, set to 1 if it is an extension
/// in the specified language, and set to 0 if disabled in the
/// specified language.
/// The C90/C99/CPP/CPP0x flags are set to 3 if the token is a keyword in a
/// future language standard, set to 2 if the token should be enabled in the
/// specified langauge, set to 1 if it is an extension in the specified
/// language, and set to 0 if disabled in the specified language.
static void AddKeyword(StringRef Keyword,
tok::TokenKind TokenCode, unsigned Flags,
const LangOptions &LangOpts, IdentifierTable &Table) {
@ -123,12 +124,15 @@ static void AddKeyword(StringRef Keyword,
else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2;
else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2;
else if (LangOpts.ObjCAutoRefCount && (Flags & KEYARC)) AddResult = 2;
else if (LangOpts.CPlusPlus && (Flags & KEYCXX0X)) AddResult = 3;
// Don't add this keyword if disabled in this language.
if (AddResult == 0) return;
IdentifierInfo &Info = Table.get(Keyword, TokenCode);
IdentifierInfo &Info =
Table.get(Keyword, AddResult == 3 ? tok::identifier : TokenCode);
Info.setIsExtensionToken(AddResult == 1);
Info.setIsCXX11CompatKeyword(AddResult == 3);
}
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
@ -493,4 +497,3 @@ const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
return 0;
}

Просмотреть файл

@ -513,6 +513,17 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
}
}
// If this identifier is a keyword in C++11, produce a warning. Don't warn if
// we're not considering macro expansion, since this identifier might be the
// name of a macro.
// FIXME: This warning is disabled in cases where it shouldn't be, like
// "#define constexpr constexpr", "int constexpr;"
if (II.isCXX11CompatKeyword() & !DisableMacroExpansion) {
Diag(Identifier, diag::warn_cxx11_keyword) << II.getName();
// Don't diagnose this keyword again in this translation unit.
II.setIsCXX11CompatKeyword(false);
}
// C++ 2.11p2: If this is an alternative representation of a C++ operator,
// then we act as if it is the actual operator and not the textual
// representation of it.

Просмотреть файл

@ -1,3 +1,36 @@
// RUN: %clang_cc1 %s -verify -fsyntax-only
int static_assert;
int char16_t;
#define thread_local __thread
thread_local int x;
#undef thread_local
namespace lib {
struct nullptr_t;
typedef nullptr_t nullptr; // expected-warning {{'nullptr' is a keyword in C++11}}
}
#define CONCAT(X,Y) CONCAT2(X,Y)
#define CONCAT2(X,Y) X ## Y
int CONCAT(constexpr,ession);
#define ID(X) X
extern int ID(decltype); // expected-warning {{'decltype' is a keyword in C++11}}
extern int CONCAT(align,of); // expected-warning {{'alignof' is a keyword in C++11}}
#define static_assert(b, s) int CONCAT(check, __LINE__)[(b) ? 1 : 0];
static_assert(1 > 0, "hello"); // ok
#define IF_CXX11(CXX11, CXX03) CXX03
typedef IF_CXX11(char16_t, wchar_t) my_wide_char_t; // ok
int alignas; // expected-warning {{'alignas' is a keyword in C++11}}
int alignof; // already diagnosed in this TU
int char16_t; // expected-warning {{'char16_t' is a keyword in C++11}}
int char32_t; // expected-warning {{'char32_t' is a keyword in C++11}}
int constexpr; // expected-warning {{'constexpr' is a keyword in C++11}}
int decltype; // already diagnosed in this TU
int noexcept; // expected-warning {{'noexcept' is a keyword in C++11}}
int nullptr; // already diagnosed in this TU
int static_assert; // expected-warning {{'static_assert' is a keyword in C++11}}
int thread_local; // expected-warning {{'thread_local' is a keyword in C++11}}

Просмотреть файл

@ -3,5 +3,5 @@
int& a();
void f() {
decltype(a()) c; // expected-error {{use of undeclared identifier 'decltype'}}
decltype(a()) c; // expected-warning {{'decltype' is a keyword in C++11}} expected-error {{use of undeclared identifier 'decltype'}}
}