From: Chris Lattner Date: Fri, 16 Jan 2009 08:21:25 +0000 (+0000) Subject: Implement basic support for parsing #pragma comment, a microsoft extension X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=636c5ef6572e899d36cec1b0023fb28ba65189e1;p=clang Implement basic support for parsing #pragma comment, a microsoft extension documented here: http://msdn.microsoft.com/en-us/library/7f0aews7(VS.80).aspx This is according to my understanding reading the docs, I don't know if it really agrees fully with what VC++ allows. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62317 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 1892ba2096..040e36b5c4 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -241,6 +241,10 @@ DIAG(err_pp_used_poisoned_id, ERROR, "attempt to use a poisoned identifier") DIAG(err__Pragma_malformed, ERROR, "_Pragma takes a parenthesized string literal") +DIAG(err_pragma_comment_malformed, ERROR, + "pragma comment requires parenthesized identifier and optional string") +DIAG(err_pragma_comment_unknown_kind, ERROR, + "unknown kind of pragma comment") DIAG(err_defined_macro_name, ERROR, "'defined' cannot be used as a macro name") DIAG(err_paste_at_start, ERROR, diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index a631a583a9..b85c725490 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -726,6 +726,7 @@ public: void HandlePragmaPoison(Token &PoisonTok); void HandlePragmaSystemHeader(Token &SysHeaderTok); void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaComment(Token &CommentTok); }; /// PreprocessorFactory - A generic factory interface for lazily creating diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index 961c0f9e6f..b19dc2009d 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -312,6 +312,74 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { } } +/// HandlePragmaComment - Handle the microsoft #pragma comment extension. The +/// syntax is: +/// #pragma comment(linker, "foo") +/// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. +/// "foo" is a string, which is fully macro expanded, and permits string +/// concatenation, embeded escape characters etc. See MSDN for more details. +void Preprocessor::HandlePragmaComment(Token &Tok) { + SourceLocation CommentLoc = Tok.getLocation(); + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Read the identifier. + Lex(Tok); + if (Tok.isNot(tok::identifier)) { + Diag(CommentLoc, diag::err_pragma_comment_malformed); + return; + } + + // Verify that this is one of the 5 whitelisted options. + // FIXME: warn that 'exestr' is deprecated. + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") && + !II->isStr("linker") && !II->isStr("user")) { + Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); + return; + } + + // Check for optional string. + // FIXME: If the kind is "compiler" warn if the string is present (it is + // ignored). + // FIXME: 'lib' requires a comment string. + // FIXME: 'linker' requires a comment string, and has a specific list of + // things that are allowable. + Lex(Tok); + if (Tok.is(tok::comma)) { + // FIXME: for now, we parse but ignore the string. + Lex(Tok); + + // We need at least one string. + if (Tok.getKind() != tok::string_literal) { + Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + + // String concatenation allows multiple strings, which can even come from + // macro expansion. + // "foo " "bar" "Baz" + while (Tok.getKind() == tok::string_literal) + Lex(Tok); + } + + if (Tok.isNot(tok::r_paren)) { + Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } + Lex(Tok); + + if (Tok.isNot(tok::eom)) { + Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); + return; + } +} + + + /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the @@ -413,6 +481,14 @@ struct PragmaDependencyHandler : public PragmaHandler { PP.HandlePragmaDependency(DepToken); } }; + +/// PragmaCommentHandler - "#pragma comment ...". +struct PragmaCommentHandler : public PragmaHandler { + PragmaCommentHandler(const IdentifierInfo *ID) : PragmaHandler(ID) {} + virtual void HandlePragma(Preprocessor &PP, Token &CommentTok) { + PP.HandlePragmaComment(CommentTok); + } +}; } // end anonymous namespace @@ -426,4 +502,8 @@ void Preprocessor::RegisterBuiltinPragmas() { getIdentifierInfo("system_header"))); AddPragmaHandler("GCC", new PragmaDependencyHandler( getIdentifierInfo("dependency"))); + + // MS extensions. + if (Features.Microsoft) + AddPragmaHandler(0, new PragmaCommentHandler(getIdentifierInfo("comment"))); } diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c new file mode 100644 index 0000000000..7a05bbcfcf --- /dev/null +++ b/test/Preprocessor/pragma_microsoft.c @@ -0,0 +1,18 @@ +// RUN: clang %s -fsyntax-only -verify -fms-extensions + +// rdar://6495941 + +#define FOO 1 +#define BAR "2" + +#pragma comment(linker,"foo=" FOO) // expected-error {{pragma comment requires parenthesized identifier and optional string}} +#pragma comment(linker," bar=" BAR) + +#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ ) + +#pragma comment(foo) // expected-error {{unknown kind of pragma comment}} +#pragma comment(compiler,) // expected-error {{pragma comment requires}} +#define foo compiler +#pragma comment(foo) // macro expand kind? +#pragma comment(foo) x // expected-error {{pragma comment requires}} +