From: Steve Naroff Date: Thu, 7 Feb 2008 03:50:06 +0000 (+0000) Subject: Implement -fms-extensions. This allows us to fuzzy parse non-standard MS constructs... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d62701bc5321049353017e9abf1963edd57646aa;p=clang Implement -fms-extensions. This allows us to fuzzy parse non-standard MS constructs used in "windows.h". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46838 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/clang.cpp b/Driver/clang.cpp index 01ef28ff38..998ac1ed86 100644 --- a/Driver/clang.cpp +++ b/Driver/clang.cpp @@ -309,6 +309,11 @@ static llvm::cl::opt PascalStrings("fpascal-strings", llvm::cl::desc("Recognize and construct Pascal-style " "string literals")); + +static llvm::cl::opt +MSExtensions("fms-extensions", + llvm::cl::desc("Accept some non-standard constructs used in " + "Microsoft header files. ")); static llvm::cl::opt WritableStrings("fwritable-strings", @@ -376,6 +381,7 @@ static void InitializeLanguageStandard(LangOptions &Options, LangKind LK) { Options.Trigraphs = 1; // -trigraphs or -ansi Options.DollarIdents = 1; // FIXME: Really a target property. Options.PascalStrings = PascalStrings; + Options.Microsoft = MSExtensions; Options.WritableStrings = WritableStrings; Options.LaxVectorConversions = LaxVectorConversions; } diff --git a/Lex/Preprocessor.cpp b/Lex/Preprocessor.cpp index a73757f1b5..40fd322550 100644 --- a/Lex/Preprocessor.cpp +++ b/Lex/Preprocessor.cpp @@ -424,7 +424,13 @@ static void InitializePredefinedMacros(Preprocessor &PP, DefineBuiltinMacro(Buf, "__cplusplus=1"); DefineBuiltinMacro(Buf, "__private_extern__=extern"); } - + if (PP.getLangOptions().Microsoft) { + DefineBuiltinMacro(Buf, "__stdcall="); + DefineBuiltinMacro(Buf, "__cdecl="); + DefineBuiltinMacro(Buf, "_cdecl="); + DefineBuiltinMacro(Buf, "__ptr64="); + DefineBuiltinMacro(Buf, "__forceinline="); + } // FIXME: Should emit a #line directive here. } diff --git a/Parse/ParseDecl.cpp b/Parse/ParseDecl.cpp index 91e77b95e0..902c5230f1 100644 --- a/Parse/ParseDecl.cpp +++ b/Parse/ParseDecl.cpp @@ -36,6 +36,48 @@ Parser::TypeTy *Parser::ParseTypeName() { return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; } +/// FuzzyParseMicrosoftDeclspec. The following construct is Microsoft's +/// equivalent of GCC's __attribute__. The grammar below is taken from +/// Microsoft's website. Unfortunately, it is incomplete. FIXME: If/when we +/// parse this for real, we will need to get a real/current grammar. +/// +/// decl-specifier: +/// '__declspec' '(' extended-decl-modifier-seq ')' +/// +/// extended-decl-modifier-seq: +/// extended-decl-modifier opt +/// extended-decl-modifier extended-decl-modifier-seq +/// +/// extended-decl-modifier: +/// align( # ) +/// allocate(" segname ") +/// appdomain +/// deprecated +/// dllimport +/// dllexport +/// jitintrinsic +/// naked +/// noalias +/// noinline +/// noreturn +/// nothrow +/// novtable +/// process +/// property({get=get_func_name|,put=put_func_name}) +/// restrict +/// selectany +/// thread +/// uuid(" ComObjectGUID ") +/// +void Parser::FuzzyParseMicrosoftDeclspec() { + assert(Tok.is(tok::kw___declspec) && "Not an declspec!"); + ConsumeToken(); + do { + ConsumeAnyToken(); + } while (ParenCount > 0 && Tok.isNot(tok::eof)); + return; +} + /// ParseAttributes - Parse a non-empty attributes list. /// /// [GNU] attributes: @@ -441,6 +483,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { case tok::kw_typedef: isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_typedef, Loc, PrevSpec); break; + case tok::kw___w64: // ignore Microsoft specifier + break; + case tok::kw___declspec: + FuzzyParseMicrosoftDeclspec(); + // Don't consume the next token, __declspec's can appear one after + // another. For example: + // __declspec(deprecated("comment1")) + // __declspec(deprecated("comment2")) extern unsigned int _winmajor; + continue; case tok::kw_extern: if (DS.isThreadSpecified()) Diag(Tok, diag::ext_thread_before, "extern"); @@ -465,9 +516,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { break; // type-specifiers + case tok::kw___int16: case tok::kw_short: isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); break; + case tok::kw___int64: case tok::kw_long: if (DS.getTypeSpecWidth() != DeclSpec::TSW_long) isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); @@ -489,9 +542,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) { case tok::kw_void: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); break; + case tok::kw___int8: case tok::kw_char: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); break; + case tok::kw___int32: case tok::kw_int: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); break; @@ -625,6 +680,9 @@ void Parser::ParseStructUnionSpecifier(DeclSpec &DS) { Tok.is(tok::kw_union) ? DeclSpec::TST_union : DeclSpec::TST_struct; SourceLocation StartLoc = ConsumeToken(); + if (getLang().Microsoft && Tok.is(tok::kw___declspec)) + FuzzyParseMicrosoftDeclspec(); + // Parse the tag portion of this. DeclTy *TagDecl; if (ParseTag(TagDecl, TagType, StartLoc)) @@ -671,7 +729,8 @@ void Parser::ParseStructDeclaration(DeclTy *TagDecl, // If there are no declarators, issue a warning. if (Tok.is(tok::semi)) { - Diag(SpecQualLoc, diag::w_no_declarators); + if (!getLang().Microsoft) // MS allows unnamed struct/union fields. + Diag(SpecQualLoc, diag::w_no_declarators); return; } diff --git a/Parse/ParseStmt.cpp b/Parse/ParseStmt.cpp index a074463f3c..052aa1a8ee 100644 --- a/Parse/ParseStmt.cpp +++ b/Parse/ParseStmt.cpp @@ -153,7 +153,9 @@ Parser::StmtResult Parser::ParseStatementOrDeclaration(bool OnlyStatement) { break; case tok::kw_asm: - Res = ParseAsmStatement(); + bool msAsm = false; + Res = ParseAsmStatement(msAsm); + if (msAsm) return Res; SemiError = "asm statement"; break; } @@ -908,6 +910,14 @@ Parser::StmtResult Parser::ParseReturnStatement() { return Actions.ActOnReturnStmt(ReturnLoc, R.Val); } +Parser::StmtResult Parser::FuzzyParseMicrosoftAsmStatement() { + unsigned short savedBraceCount = BraceCount; + do { + ConsumeAnyToken(); + } while (BraceCount > savedBraceCount && Tok.isNot(tok::eof)); + return false; +} + /// ParseAsmStatement - Parse a GNU extended asm statement. /// [GNU] asm-statement: /// 'asm' type-qualifier[opt] '(' asm-argument ')' ';' @@ -923,10 +933,14 @@ Parser::StmtResult Parser::ParseReturnStatement() { /// asm-string-literal /// asm-clobbers ',' asm-string-literal /// -Parser::StmtResult Parser::ParseAsmStatement() { +Parser::StmtResult Parser::ParseAsmStatement(bool &msAsm) { assert(Tok.is(tok::kw_asm) && "Not an asm stmt"); SourceLocation AsmLoc = ConsumeToken(); + if (Tok.is(tok::l_brace)) { + msAsm = true; + return FuzzyParseMicrosoftAsmStatement(); + } DeclSpec DS; SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS); diff --git a/Sema/SemaDecl.cpp b/Sema/SemaDecl.cpp index 3eb752dcf4..cd546f3efc 100644 --- a/Sema/SemaDecl.cpp +++ b/Sema/SemaDecl.cpp @@ -228,8 +228,9 @@ TypedefDecl *Sema::MergeTypeDefDecl(TypedefDecl *New, ScopedDecl *OldD) { DirectoryLookup::DirType OldDirType = HdrInfo.getFileDirFlavor(OldDeclFile); DirectoryLookup::DirType NewDirType = HdrInfo.getFileDirFlavor(NewDeclFile); - if (OldDirType == DirectoryLookup::ExternCSystemHeaderDir || - NewDirType == DirectoryLookup::ExternCSystemHeaderDir) + if ((OldDirType == DirectoryLookup::ExternCSystemHeaderDir || + NewDirType == DirectoryLookup::ExternCSystemHeaderDir) || + getLangOptions().Microsoft) return New; // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope. diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 31d6bc74bb..6f43840835 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -302,6 +302,14 @@ KEYWORD(__thread , EXTC90|EXTC99|EXTCPP|EXTCPP0x) // Apple Extension. KEYWORD(__private_extern__ , EXTC90|EXTC99|NOTCPP) +// Microsoft Extensions. +KEYWORD(__w64 , EXTC90|EXTC99|NOTCPP) +KEYWORD(__declspec , EXTC90|EXTC99|NOTCPP) +KEYWORD(__int8 , EXTC90|EXTC99|NOTCPP) +KEYWORD(__int16 , EXTC90|EXTC99|NOTCPP) +KEYWORD(__int32 , EXTC90|EXTC99|NOTCPP) +KEYWORD(__int64 , EXTC90|EXTC99|NOTCPP) + // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. ALIAS("__attribute__", __attribute) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 2dbae31339..2712daa245 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -130,6 +130,8 @@ private: return ConsumeBracket(); else if (isTokenBrace()) return ConsumeBrace(); + else if (isTokenStringLiteral()) + return ConsumeStringToken(); else return ConsumeToken(); } @@ -402,7 +404,8 @@ private: StmtResult ParseContinueStatement(); StmtResult ParseBreakStatement(); StmtResult ParseReturnStatement(); - StmtResult ParseAsmStatement(); + StmtResult ParseAsmStatement(bool &msAsm); + StmtResult FuzzyParseMicrosoftAsmStatement(); StmtResult ParseObjCAtStatement(SourceLocation atLoc); StmtResult ParseObjCTryStmt(SourceLocation atLoc, bool &processAtKeyword); StmtResult ParseObjCThrowStmt(SourceLocation atLoc); @@ -438,6 +441,7 @@ private: bool isTypeSpecifierQualifier() const; TypeTy *ParseTypeName(); + void FuzzyParseMicrosoftDeclspec(); AttributeList *ParseAttributes(); void ParseTypeofSpecifier(DeclSpec &DS);