]> granicus.if.org Git - clang/commitdiff
Add support for Microsoft __if_exists and __if_not_exists construct inside function...
authorFrancois Pichet <pichet2000@gmail.com>
Fri, 6 May 2011 20:48:22 +0000 (20:48 +0000)
committerFrancois Pichet <pichet2000@gmail.com>
Fri, 6 May 2011 20:48:22 +0000 (20:48 +0000)
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
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/Parse/ParseStmt.cpp
lib/Sema/SemaExprCXX.cpp
test/Parser/MicrosoftExtensions.cpp

index f9d1f4ef158e2cd2257dc71be2d49f390b4622c7..131bfe3afea98e240931325ebbb779286d7d917e 100644 (file)
@@ -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)
index 3fd9844368ee4b95f1905540ee15c2ffa14a8cc5..adf72d0a4b99aa7eaa7865cbd644ef799bfcee63 100644 (file)
@@ -1308,7 +1308,8 @@ private:
   StmtResult ParseReturnStatement(ParsedAttributes &Attr);
   StmtResult ParseAsmStatement(bool &msAsm);
   StmtResult FuzzyParseMicrosoftAsmStatement(SourceLocation AsmLoc);
-  bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
+  void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
+bool ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names,
                            llvm::SmallVectorImpl<ExprTy *> &Constraints,
                            llvm::SmallVectorImpl<ExprTy *> &Exprs);
 
index 1ce7f6af5b6e7204a2bc1cc534c9f8d5c6cf7f42..f741bc06d4ef0fc46306e4feddae814ec0aba0bf 100644 (file)
@@ -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
index f0ab531080338aa4548117790030246b4570c45b..12ab5e2767ee8a2f2b4055ccc8a677123858dbc0 100644 (file)
@@ -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();
+}
index 7f1bf596a2375dd662298cecb6079a041094c452..e9aa1d3bcf8e893e4ee4ed3a87269564df11ee9f 100644 (file)
@@ -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(); 
+}
index 32ed375889a65dbd20c31b44c4066b593e70ddf1..933231d5f70c06fe4fd8e2c9e7365023c737789e 100644 (file)
@@ -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++;
+  }
+
+}