From: Richard Smith Date: Sat, 15 Mar 2014 00:06:08 +0000 (+0000) Subject: Implement the MS extension __identifier properly: take a token and strip it of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9158025c87f1fd42ecbb2549ac5542c7f2f6a1f7;p=clang Implement the MS extension __identifier properly: take a token and strip it of its keywordliness. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203987 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 86b0f080fb..e1fc72f8ae 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -403,6 +403,9 @@ def warn_has_warning_invalid_option : ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">, InGroup; +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; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 299c06a1ef..56c85d4f91 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -116,6 +116,7 @@ class Preprocessor : public RefCountedBase { 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 diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index a5b0267355..761dba427e 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -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) diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 55b3bd5b89..78d4e14ccd 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -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!"); } diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 2ed0c8ad59..5f3c2a26fc 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -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 token to an identifier}} + __identifier(+) // expected-error {{cannot convert '+' token to an identifier}} + __identifier("foo") // expected-error {{cannot convert 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}}