From 1e862693c63067ae467b0b3884c44f753cd6e821 Mon Sep 17 00:00:00 2001 From: Francois Pichet Date: Fri, 6 May 2011 20:48:22 +0000 Subject: [PATCH] Add support for Microsoft __if_exists and __if_not_exists construct inside function definition. Allow to include or exclude code depending on if a symbol exists or not. Just like a #ifdef but for C/C++ symbols. More doc: http://msdn.microsoft.com/en-us/library/x7wy9xh3(v=VS.100).aspx Support at class and namespace scopes will be added later. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131014 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/TokenKinds.def | 2 + include/clang/Parse/Parser.h | 3 +- include/clang/Sema/Sema.h | 2 + lib/Parse/ParseStmt.cpp | 70 +++++++++++++++++++++++++++++ lib/Sema/SemaExprCXX.cpp | 15 +++++++ test/Parser/MicrosoftExtensions.cpp | 33 ++++++++++++++ 6 files changed, 124 insertions(+), 1 deletion(-) diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index f9d1f4ef15..131bfe3afe 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -451,6 +451,8 @@ KEYWORD(__except , KEYMS | KEYBORLAND) KEYWORD(__finally , KEYMS | KEYBORLAND) KEYWORD(__leave , KEYMS | KEYBORLAND) KEYWORD(__int64 , KEYMS) +KEYWORD(__if_exists , KEYMS) +KEYWORD(__if_not_exists , KEYMS) ALIAS("__int8" , char , KEYMS) ALIAS("__int16" , short , KEYMS) ALIAS("__int32" , int , KEYMS) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 3fd9844368..adf72d0a4b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1308,7 +1308,8 @@ private: StmtResult ParseReturnStatement(ParsedAttributes &Attr); StmtResult ParseAsmStatement(bool &msAsm); StmtResult FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc); - bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, + void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); +bool ParseAsmOperandsOpt(llvm::SmallVectorImpl &Names, llvm::SmallVectorImpl &Constraints, llvm::SmallVectorImpl &Exprs); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1ce7f6af5b..f741bc06d4 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2385,6 +2385,8 @@ public: bool CheckCaseExpression(Expr *expr); + bool CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, UnqualifiedId &Name); + //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index f0ab531080..12ab5e2767 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -741,6 +741,12 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { continue; } + if (getLang().Microsoft && (Tok.is(tok::kw___if_exists) || + Tok.is(tok::kw___if_not_exists))) { + ParseMicrosoftIfExistsStatement(Stmts); + continue; + } + StmtResult R; if (Tok.isNot(tok::kw___extension__)) { R = ParseStatementOrDeclaration(Stmts, false); @@ -2000,3 +2006,67 @@ StmtResult Parser::ParseCXXCatchBlock() { return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take()); } + +void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) { + assert((Tok.is(tok::kw___if_exists) || Tok.is(tok::kw___if_not_exists)) && + "Expected '__if_exists' or '__if_not_exists'"); + Token Condition = Tok; + SourceLocation IfExistsLoc = ConsumeToken(); + + SourceLocation LParenLoc = Tok.getLocation(); + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen_after) << IfExistsLoc; + SkipUntil(tok::semi); + return; + } + ConsumeParen(); // eat the '('. + + // Parse nested-name-specifier. + CXXScopeSpec SS; + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); + + // Check nested-name specifier. + if (SS.isInvalid()) { + SkipUntil(tok::semi); + return; + } + + // Parse the unqualified-id. + UnqualifiedId Name; + if (ParseUnqualifiedId(SS, false, true, true, ParsedType(), Name)) { + SkipUntil(tok::semi); + return; + } + + if (MatchRHSPunctuation(tok::r_paren, LParenLoc).isInvalid()) + return; + + if (Tok.isNot(tok::l_brace)) { + Diag(Tok, diag::err_expected_lbrace); + return; + } + ConsumeBrace(); + + // Check if the symbol exists. + bool Exist = Actions.CheckMicrosoftIfExistsSymbol(SS, Name); + + // If the condition is false skip the tokens until the '}' + if ((Condition.is(tok::kw___if_exists) && !Exist) || + (Condition.is(tok::kw___if_not_exists) && Exist)) { + SkipUntil(tok::r_brace, false); + return; + } + + // Condition is true, parse the statements. + while (Tok.isNot(tok::r_brace)) { + StmtResult R = ParseStatementOrDeclaration(Stmts, false); + if (R.isUsable()) + Stmts.push_back(R.release()); + } + + if (Tok.isNot(tok::r_brace)) { + Diag(Tok, diag::err_expected_rbrace); + return; + } + ConsumeBrace(); +} diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7f1bf596a2..e9aa1d3bcf 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4295,3 +4295,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } + +bool Sema::CheckMicrosoftIfExistsSymbol(CXXScopeSpec &SS, + UnqualifiedId &Name) { + DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); + DeclarationName TargetName = TargetNameInfo.getName(); + if (!TargetName) + return false; + + // Do the redeclaration lookup in the current scope. + LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, + Sema::NotForRedeclaration); + R.suppressDiagnostics(); + LookupParsedName(R, getCurScope(), &SS); + return !R.empty(); +} diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 32ed375889..933231d5f7 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -164,3 +164,36 @@ __interface MicrosoftInterface { }; __int64 x7 = __int64(0); + + + + +class IF_EXISTS { +private: + typedef int Type; +}; + +int __if_exists_test() { + + int b=0; + + + __if_exists(IF_EXISTS::Type) { + b++; + b++; + } + + __if_exists(IF_EXISTS::Type_not) { + this wont compile. + } + + __if_not_exists(IF_EXISTS::Type) { + this wont compile. + } + + __if_not_exists(IF_EXISTS::Type_not) { + b++; + b++; + } + +} -- 2.40.0