diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticLexKinds.td | 3 | ||||
| -rw-r--r-- | clang/include/clang/Lex/Preprocessor.h | 1 | ||||
| -rw-r--r-- | clang/lib/Frontend/InitPreprocessor.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Lex/PPMacroExpansion.cpp | 53 | ||||
| -rw-r--r-- | clang/test/Parser/MicrosoftExtensions.cpp | 23 | 
5 files changed, 74 insertions, 10 deletions
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 86b0f080fb8..e1fc72f8ae2 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/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<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>; diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 299c06a1efe..56c85d4f912 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -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 diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index a5b02673555..761dba427e3 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/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/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 55b3bd5b89e..78d4e14ccd6 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/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/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp index 2ed0c8ad59b..5f3c2a26fc0 100644 --- a/clang/test/Parser/MicrosoftExtensions.cpp +++ b/clang/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 <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}}  | 

