Implement the MS extension __identifier properly: take a token and strip it of

its keywordliness.

llvm-svn: 203987
This commit is contained in:
Richard Smith 2014-03-15 00:06:08 +00:00
parent cec949af13
commit ae385084c5
5 changed files with 74 additions and 10 deletions

View File

@ -403,6 +403,9 @@ def warn_has_warning_invalid_option :
ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">,
InGroup<MalformedWarningCheck>;
def err_pp_identifier_arg_not_identifier : Error<
"cannot convert %0 token to an identifier">;
def warn_pragma_include_alias_mismatch_angle :
ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted "
"include \"%1\"">, InGroup<UnknownPragmas>;

View File

@ -116,6 +116,7 @@ class Preprocessor : public RefCountedBase<Preprocessor> {
IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__
IdentifierInfo *Ident__COUNTER__; // __COUNTER__
IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma
IdentifierInfo *Ident__identifier; // __identifier
IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__
IdentifierInfo *Ident__has_feature; // __has_feature
IdentifierInfo *Ident__has_extension; // __has_extension

View File

@ -517,10 +517,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
Builder.defineMacro("_WCHAR_T_DEFINED");
Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED");
}
if (LangOpts.CPlusPlus) {
// FIXME: Support Microsoft's __identifier extension in the lexer.
Builder.append("#define __identifier(x) x");
}
}
if (LangOpts.Optimize)

View File

@ -97,6 +97,15 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__");
Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__");
// Microsoft Extensions.
if (LangOpts.MicrosoftExt) {
Ident__identifier = RegisterBuiltinMacro(*this, "__identifier");
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
} else {
Ident__identifier = 0;
Ident__pragma = 0;
}
// Clang Extensions.
Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature");
Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension");
@ -119,12 +128,6 @@ void Preprocessor::RegisterBuiltinMacros() {
Ident__building_module = 0;
Ident__MODULE__ = 0;
}
// Microsoft Extensions.
if (LangOpts.MicrosoftExt)
Ident__pragma = RegisterBuiltinMacro(*this, "__pragma");
else
Ident__pragma = 0;
}
/// isTrivialSingleTokenExpansion - Return true if MI, which has a single token
@ -1481,6 +1484,44 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule);
Tok.setIdentifierInfo(ModuleII);
Tok.setKind(ModuleII->getTokenID());
} else if (II == Ident__identifier) {
SourceLocation Loc = Tok.getLocation();
// We're expecting '__identifier' '(' identifier ')'. Try to recover
// if the parens are missing.
LexNonComment(Tok);
if (Tok.isNot(tok::l_paren)) {
// No '(', use end of last token.
Diag(getLocForEndOfToken(Loc), diag::err_pp_expected_after)
<< II << tok::l_paren;
// If the next token isn't valid as our argument, we can't recover.
if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
Tok.setKind(tok::identifier);
return;
}
SourceLocation LParenLoc = Tok.getLocation();
LexNonComment(Tok);
if (!Tok.isAnnotation() && Tok.getIdentifierInfo())
Tok.setKind(tok::identifier);
else {
Diag(Tok.getLocation(), diag::err_pp_identifier_arg_not_identifier)
<< Tok.getKind();
// Don't walk past anything that's not a real token.
if (Tok.is(tok::eof) || Tok.is(tok::eod) || Tok.isAnnotation())
return;
}
// Discard the ')', preserving 'Tok' as our result.
Token RParen;
LexNonComment(RParen);
if (RParen.isNot(tok::r_paren)) {
Diag(getLocForEndOfToken(Tok.getLocation()), diag::err_pp_expected_after)
<< Tok.getKind() << tok::r_paren;
Diag(LParenLoc, diag::note_matching) << tok::l_paren;
}
return;
} else {
llvm_unreachable("Unknown identifier!");
}

View File

@ -325,6 +325,29 @@ class IF_EXISTS_CLASS_TEST {
int __identifier(generic) = 3;
int __identifier(int) = 4;
struct __identifier(class) { __identifier(class) *__identifier(for); };
__identifier(class) __identifier(struct) = { &__identifier(struct) };
int __identifier for; // expected-error {{missing '(' after '__identifier'}}
int __identifier(else} = __identifier(for); // expected-error {{missing ')' after identifier}} expected-note {{to match this '('}}
#define identifier_weird(x) __identifier(x
int k = identifier_weird(if)); // expected-error {{use of undeclared identifier 'if'}}
// This is a bit weird, but the alternative tokens aren't keywords, and this
// behavior matches MSVC. FIXME: Consider supporting this anyway.
extern int __identifier(and) r; // expected-error {{cannot convert '&&' token to an identifier}}
void f() {
__identifier(() // expected-error {{cannot convert '(' token to an identifier}}
__identifier(void) // expected-error {{use of undeclared identifier 'void'}}
__identifier()) // expected-error {{cannot convert ')' token to an identifier}}
// FIXME: We should pick a friendlier display name for this token kind.
__identifier(1) // expected-error {{cannot convert <numeric_constant> token to an identifier}}
__identifier(+) // expected-error {{cannot convert '+' token to an identifier}}
__identifier("foo") // expected-error {{cannot convert <string_literal> token to an identifier}}
__identifier(;) // expected-error {{cannot convert ';' token to an identifier}}
}
class inline_definition_pure_spec {
virtual int f() = 0 { return 0; }// expected-warning {{function definition with pure-specifier is a Microsoft extension}}