Preprocessor: support defined() with operator names for MS compatibility

Also flesh out missing tests, improve diagnostic QOI and fix a couple of corner
cases found in the process.

Fixes PR10606.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209276 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alp Toker 2014-05-21 06:13:51 +00:00
parent d685fc0ecc
commit 4f6988e487
9 changed files with 100 additions and 65 deletions

View File

@ -353,7 +353,7 @@ def err_pp_error_opening_file : Error<
def err_pp_empty_filename : Error<"empty filename">;
def err_pp_include_too_deep : Error<"#include nested too deeply">;
def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">;
def err_pp_macro_not_identifier : Error<"macro names must be identifiers">;
def err_pp_macro_not_identifier : Error<"macro name must be an identifier">;
def err_pp_missing_macro_name : Error<"macro name missing">;
def err_pp_missing_rparen_in_macro_def : Error<
"missing ')' in macro parameter list">;
@ -379,8 +379,6 @@ def err_pp_expected_value_in_expr : Error<"expected value in expression">;
def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">;
def err_pp_expected_eol : Error<
"expected end of line in preprocessor expression">;
def err_pp_defined_requires_identifier : Error<
"operator 'defined' requires an identifier">;
def err_pp_expected_after : Error<"missing %1 after %0">;
def err_pp_colon_without_question : Error<"':' without preceding '?'">;
def err_pp_division_by_zero : Error<

View File

@ -1343,6 +1343,8 @@ public:
/// followed by EOD. Return true if the token is not a valid on-off-switch.
bool LexOnOffSwitch(tok::OnOffSwitch &OOS);
bool CheckMacroName(Token &MacroNameTok, char isDefineUndef);
private:
void PushIncludeMacroStack() {

View File

@ -129,6 +129,51 @@ void Preprocessor::DiscardUntilEndOfDirective() {
} while (Tmp.isNot(tok::eod));
}
bool Preprocessor::CheckMacroName(Token &MacroNameTok, char isDefineUndef) {
// Missing macro name?
if (MacroNameTok.is(tok::eod))
return Diag(MacroNameTok, diag::err_pp_missing_macro_name);
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
if (!II) {
bool Invalid = false;
std::string Spelling = getSpelling(MacroNameTok, &Invalid);
if (Invalid)
return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
const IdentifierInfo &Info = Identifiers.get(Spelling);
// Allow #defining |and| and friends in microsoft mode.
if (Info.isCPlusPlusOperatorKeyword() && getLangOpts().MSVCCompat) {
MacroNameTok.setIdentifierInfo(getIdentifierInfo(Spelling));
return false;
}
if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
return Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name)
<< Spelling;
return Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
}
if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
// Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
return Diag(MacroNameTok, diag::err_defined_macro_name);
}
if (isDefineUndef == 2 && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
// Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
// and C++ [cpp.predefined]p4], but allow it as an extension.
Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
}
// Okay, we got a good identifier.
return false;
}
/// \brief Lex and validate a macro name, which occurs after a
/// \#define or \#undef.
///
@ -146,53 +191,16 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) {
setCodeCompletionReached();
LexUnexpandedToken(MacroNameTok);
}
// Missing macro name?
if (MacroNameTok.is(tok::eod)) {
Diag(MacroNameTok, diag::err_pp_missing_macro_name);
if (!CheckMacroName(MacroNameTok, isDefineUndef))
return;
// Invalid macro name, read and discard the rest of the line and set the
// token kind to tok::eod if necessary.
if (MacroNameTok.isNot(tok::eod)) {
MacroNameTok.setKind(tok::eod);
DiscardUntilEndOfDirective();
}
IdentifierInfo *II = MacroNameTok.getIdentifierInfo();
if (!II) {
bool Invalid = false;
std::string Spelling = getSpelling(MacroNameTok, &Invalid);
if (Invalid)
return;
const IdentifierInfo &Info = Identifiers.get(Spelling);
// Allow #defining |and| and friends in microsoft mode.
if (Info.isCPlusPlusOperatorKeyword() && getLangOpts().MSVCCompat) {
MacroNameTok.setIdentifierInfo(getIdentifierInfo(Spelling));
return;
}
if (Info.isCPlusPlusOperatorKeyword())
// C++ 2.5p2: Alternative tokens behave the same as its primary token
// except for their spellings.
Diag(MacroNameTok, diag::err_pp_operator_used_as_macro_name) << Spelling;
else
Diag(MacroNameTok, diag::err_pp_macro_not_identifier);
// Fall through on error.
} else if (isDefineUndef && II->getPPKeywordID() == tok::pp_defined) {
// Error if defining "defined": C99 6.10.8/4, C++ [cpp.predefined]p4.
Diag(MacroNameTok, diag::err_defined_macro_name);
} else if (isDefineUndef == 2 && II->hasMacroDefinition() &&
getMacroInfo(II)->isBuiltinMacro()) {
// Warn if undefining "__LINE__" and other builtins, per C99 6.10.8/4
// and C++ [cpp.predefined]p4], but allow it as an extension.
Diag(MacroNameTok, diag::ext_pp_undef_builtin_macro);
return;
} else {
// Okay, we got a good identifier node. Return it.
return;
}
// Invalid macro name, read and discard the rest of the line. Then set the
// token kind to tok::eod.
MacroNameTok.setKind(tok::eod);
return DiscardUntilEndOfDirective();
}
/// \brief Ensure that the next token is a tok::eod token.

View File

@ -81,7 +81,6 @@ struct DefinedTracker {
/// EvaluateDefined - Process a 'defined(sym)' expression.
static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
bool ValueLive, Preprocessor &PP) {
IdentifierInfo *II;
SourceLocation beginLoc(PeekTok.getLocation());
Result.setBegin(beginLoc);
@ -102,14 +101,13 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
PP.setCodeCompletionReached();
PP.LexUnexpandedNonComment(PeekTok);
}
// If we don't have a pp-identifier now, this is an error.
if ((II = PeekTok.getIdentifierInfo()) == nullptr) {
PP.Diag(PeekTok, diag::err_pp_defined_requires_identifier);
if (PP.CheckMacroName(PeekTok, 0))
return true;
}
// Otherwise, we got an identifier, is it defined to something?
IdentifierInfo *II = PeekTok.getIdentifierInfo();
Result.Val = II->hasMacroDefinition();
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.

View File

@ -139,7 +139,7 @@ void operator""_\u212e""_\u212f(unsigned long long) {} // expected-error {{diffe
void operator""_""_(unsigned long long) {} // expected-note {{previous}}
void operator""_\u212e""_\u212e(unsigned long long) {} // expected-error {{redefinition}}
#define ¢ *0.01 // expected-error {{macro names must be identifiers}}
#define ¢ *0.01 // expected-error {{macro name must be an identifier}}
constexpr int operator""_¢(long double d) { return d * 100; } // expected-error {{non-ASCII}}
constexpr int operator""_¢(unsigned long long n) { return n; } // expected-error {{non-ASCII}}
static_assert(0.02_¢ == 2_¢, ""); // expected-error 2{{non-ASCII}}

View File

@ -1,7 +1,22 @@
// RUN: not %clang_cc1 %s -E
// RUN: %clang_cc1 %s -E -fno-operator-names
// RUN: %clang_cc1 %s -E -verify -DOPERATOR_NAMES
// RUN: %clang_cc1 %s -E -verify -fno-operator-names
// Not valid in C++ unless -fno-operator-names is passed.
#ifndef OPERATOR_NAMES
//expected-error@+3 {{token is not a valid binary operator in a preprocessor subexpression}}
#endif
// Valid because 'and' is a spelling of '&&'
#if defined foo and bar
#endif
// Not valid in C++ unless -fno-operator-names is passed:
#ifdef OPERATOR_NAMES
//expected-error@+2 {{C++ operator 'and' cannot be used as a macro name}}
#endif
#define and foo
#ifdef OPERATOR_NAMES
//expected-error@+2 {{C++ operator 'and' cannot be used as a macro name}}
#endif
#if defined and
#endif

View File

@ -7,6 +7,13 @@ bool f() {
#endif
}
#ifdef and
#endif
// The second 'and' is a valid C++ operator name for '&&'.
#if defined and and defined(and)
#endif
// All c++ keywords should be #define-able in ms mode.
// (operators like "and" aren't normally, the rest always is.)
#define and

View File

@ -1,15 +1,22 @@
/* RUN: not %clang_cc1 -E %s 2>&1 >/dev/null | grep error: | count 3
/* RUN: %clang_cc1 -E -verify %s
*/
/* expected-error@+1 {{macro name missing}} */
#ifdef
#endif
/* End of function-like macro invocation in #ifdef */
/* expected-error@+1 {{macro name must be an identifier}} */
#ifdef !
#endif
/* expected-error@+1 {{macro name missing}} */
#if defined
#endif
/* PR1936 */
/* expected-error@+2 {{unterminated function-like macro invocation}} expected-error@+2 {{expected value in expression}} expected-note@+1 {{macro 'f' defined here}} */
#define f(x) x
#if f(2
#endif
int x;

View File

@ -24,9 +24,9 @@
#endif
// Make sure we reject disallowed UCNs
#define \ufffe // expected-error {{macro names must be identifiers}}
#define \U10000000 // expected-error {{macro names must be identifiers}}
#define \u0061 // expected-error {{character 'a' cannot be specified by a universal character name}} expected-error {{macro names must be identifiers}}
#define \ufffe // expected-error {{macro name must be an identifier}}
#define \U10000000 // expected-error {{macro name must be an identifier}}
#define \u0061 // expected-error {{character 'a' cannot be specified by a universal character name}} expected-error {{macro name must be an identifier}}
// FIXME: Not clear what our behavior should be here; \u0024 is "$".
#define a\u0024 // expected-warning {{whitespace}}