]> granicus.if.org Git - clang/commitdiff
Implement support for dependent Microsoft __if_exists/__if_not_exists
authorDouglas Gregor <dgregor@apple.com>
Tue, 25 Oct 2011 01:33:02 +0000 (01:33 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 25 Oct 2011 01:33:02 +0000 (01:33 +0000)
statements. As noted in the documentation for the AST node, the
semantics of __if_exists/__if_not_exists are somewhat different from
the way Visual C++ implements them, because our parsed-template
representation can't accommodate VC++ semantics without serious
contortions. Hopefully this implementation is "good enough".

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142901 91177308-0d34-0410-b5e6-96231b3b80d8

21 files changed:
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/AST/StmtCXX.h
include/clang/Basic/StmtNodes.td
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGStmt.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Index/ms-if-exists.cpp [new file with mode: 0644]
test/PCH/ms-if-exists.cpp [new file with mode: 0644]
test/SemaTemplate/ms-if-exists.cpp
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index 0ec09c9b09e06cfef3cb6afd38014afa7f4603a0..a47f7008a299a4adfa2a5c409caabfebc533f627 100644 (file)
@@ -1735,6 +1735,9 @@ DEF_TRAVERSE_STMT(ObjCAtTryStmt, { })
 DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { })
 DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { })
 DEF_TRAVERSE_STMT(CXXForRangeStmt, { })
+DEF_TRAVERSE_STMT(MSDependentExistsStmt, { 
+    TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
+})
 DEF_TRAVERSE_STMT(ReturnStmt, { })
 DEF_TRAVERSE_STMT(SwitchStmt, { })
 DEF_TRAVERSE_STMT(WhileStmt, { })
index 2a6fd6bc964cccf008aebb9f6cb3d96dba6f80f9..8840719413d52a3ea05c93ce620498f30ad9af91 100644 (file)
@@ -1596,9 +1596,8 @@ public:
   }
 
   static bool classof(SEHTryStmt *) { return true; }
-
 };
-
+  
 }  // end namespace clang
 
 #endif
index 42dcf2bb7b79053d45da0801dccf89a7aa15ca4f..056a0a393caea01aba6081eee5cf2a6c5c7dc7ba 100644 (file)
@@ -201,6 +201,91 @@ public:
   }
 };
 
+/// \brief Representation of a Microsoft __if_exists or __if_not_exists
+/// statement with a dependent name.
+///
+/// The __if_exists statement can be used to include a sequence of statements
+/// in the program only when a particular dependent name does not exist. For
+/// example:
+///
+/// \code
+/// template<typename T> 
+/// void call_foo(T &t) {
+///   __if_exists (T::foo) {
+///     t.foo(); // okay: only called when T::foo exists. 
+///   }
+/// }
+/// \endcode
+///
+/// Similarly, the __if_not_exists statement can be used to include the
+/// statements when a particular name does not exist.
+///
+/// Note that this statement only captures __if_exists and __if_not_exists
+/// statements whose name is dependent. All non-dependent cases are handled
+/// directly in the parser, so that they don't introduce a new scope. Clang
+/// introduces scopes in the dependent case to keep names inside the compound
+/// statement from leaking out into the surround statements, which would
+/// compromise the template instantiation model. This behavior differs from
+/// Visual C++ (which never introduces a scope), but is a fairly reasonable
+/// approximation of the VC++ behavior.
+class MSDependentExistsStmt : public Stmt {
+  SourceLocation KeywordLoc;
+  bool IsIfExists;
+  NestedNameSpecifierLoc QualifierLoc;
+  DeclarationNameInfo NameInfo;
+  Stmt *SubStmt;
+  
+  friend class ASTReader;
+  friend class ASTStmtReader;
+  
+public:
+  MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, 
+                        NestedNameSpecifierLoc QualifierLoc,
+                        DeclarationNameInfo NameInfo,
+                        CompoundStmt *SubStmt)
+  : Stmt(MSDependentExistsStmtClass),
+    KeywordLoc(KeywordLoc), IsIfExists(IsIfExists), 
+    QualifierLoc(QualifierLoc), NameInfo(NameInfo),
+    SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { }
+  
+  /// \brief Retrieve the location of the __if_exists or __if_not_exists 
+  /// keyword.
+  SourceLocation getKeywordLoc() const { return KeywordLoc; }
+  
+  /// \brief Determine whether this is an __if_exists statement.
+  bool isIfExists() const { return IsIfExists; }
+
+  /// \brief Determine whether this is an __if_exists statement.
+  bool isIfNotExists() const { return !IsIfExists; }
+  
+  /// \brief Retrieve the nested-name-specifier that qualifies this name, if
+  /// any.
+  NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
+  
+  /// \brief Retrieve the name of the entity we're testing for, along with
+  /// location information
+  DeclarationNameInfo getNameInfo() const { return NameInfo; }
+  
+  /// \brief Retrieve the compound statement that will be included in the
+  /// program only if the existence of the symbol matches the initial keyword.
+  CompoundStmt *getSubStmt() const { 
+    return reinterpret_cast<CompoundStmt *>(SubStmt); 
+  }
+  
+  SourceRange getSourceRange() const {
+    return SourceRange(KeywordLoc, SubStmt->getLocEnd());
+  }
+  
+  child_range children() {
+    return child_range(&SubStmt, &SubStmt+1);
+  }
+  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == MSDependentExistsStmtClass;
+  }
+  
+  static bool classof(MSDependentExistsStmt *) { return true; }
+};
 
 }  // end namespace clang
 
index 7b3d7762c24aa551a8540285a7a616582d466a64..02aec8cfef505ebc40e733776d0657a1fb520fe1 100644 (file)
@@ -155,6 +155,7 @@ def CXXUuidofExpr : DStmt<Expr>;
 def SEHTryStmt : Stmt;
 def SEHExceptStmt : Stmt;
 def SEHFinallyStmt : Stmt;
+def MSDependentExistsStmt : Stmt;
 
 // OpenCL Extensions.
 def AsTypeExpr : DStmt<Expr>;
index 22a308dd2acfd8b3efafc7567f562b1c6ec0db23..f3634f1c110621332e8f39eec4dd98e40eeabb29 100644 (file)
@@ -2602,10 +2602,24 @@ public:
     /// \brief The name is a dependent name, so it 
     IER_Dependent
   };
-  
+
+  IfExistsResult 
+  CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, 
+                               const DeclarationNameInfo &TargetNameInfo);
+
   IfExistsResult 
   CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Name);
 
+  StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+                                        bool IsIfExists,
+                                        NestedNameSpecifierLoc QualifierLoc,
+                                        DeclarationNameInfo NameInfo,
+                                        Stmt *Nested);
+  StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, 
+                                        bool IsIfExists,
+                                        CXXScopeSpec &SS, UnqualifiedId &Name,
+                                        Stmt *Nested);
+  
   //===------------------------- "Block" Extension ------------------------===//
 
   /// ActOnBlockStart - This callback is invoked when a block literal is
index 49f1ddfa26b37cfd091ce1e33a5780c5b53fa279..d237f1b6345ee90cd7edc6b3cfa6827fcf02972c 100644 (file)
@@ -1099,7 +1099,9 @@ namespace clang {
       STMT_SEH_TRY,               // SEHTryStmt
       
       // ARC
-      EXPR_OBJC_BRIDGED_CAST       // ObjCBridgedCastExpr
+      EXPR_OBJC_BRIDGED_CAST,     // ObjCBridgedCastExpr
+      
+      STMT_MS_DEPENDENT_EXISTS    // MSDependentExistsStmt
     };
 
     /// \brief The kinds of designators that can occur in a
index daaa354ac342c5bd4ccc8c467a39a947e1ae0244..5b1654c92402167bc62d0c3213cef0c7e66785c8 100644 (file)
@@ -305,6 +305,22 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
   Indent() << "}\n";
 }
 
+void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
+  Indent();
+  if (Node->isIfExists())
+    OS << "__if_exists (";
+  else
+    OS << "__if_not_exists (";
+  
+  if (NestedNameSpecifier *Qualifier
+        = Node->getQualifierLoc().getNestedNameSpecifier())
+    Qualifier->print(OS, Policy);
+  
+  OS << Node->getNameInfo() << ") ";
+  
+  PrintRawCompoundStmt(Node->getSubStmt());
+}
+
 void StmtPrinter::VisitGotoStmt(GotoStmt *Node) {
   Indent() << "goto " << Node->getLabel()->getName() << ";\n";
 }
index 214378a974a6b4b49fab7586f73596de093a854b..93b2f65818396983fd4c1943c93d90b620677c88 100644 (file)
@@ -182,6 +182,13 @@ void StmtProfiler::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitMSDependentExistsStmt(const MSDependentExistsStmt *S) {
+  VisitStmt(S);
+  ID.AddBoolean(S->isIfExists());
+  VisitNestedNameSpecifier(S->getQualifierLoc().getNestedNameSpecifier());
+  VisitName(S->getNameInfo().getName());
+}
+
 void StmtProfiler::VisitSEHTryStmt(const SEHTryStmt *S) {
   VisitStmt(S);
 }
index c56931bbc6fa0782630dc3ef4f03214990388f4d..6f020ccab0fdc0a6c9945ca1f4886f9625895ae9 100644 (file)
@@ -73,6 +73,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
   case Stmt::CXXCatchStmtClass:
   case Stmt::SEHExceptStmtClass:
   case Stmt::SEHFinallyStmtClass:
+  case Stmt::MSDependentExistsStmtClass:
     llvm_unreachable("invalid statement class to emit generically");
   case Stmt::NullStmtClass:
   case Stmt::CompoundStmtClass:
index 5c2ed4e5f52bdaa0a31f8731be4eee8c6c4aee38..fb884349291305f9ebaa71beadf2dcd5c0d6c786 100644 (file)
@@ -2152,7 +2152,16 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
     
     ParsedAttributes Attrs(AttrFactory);
     StmtResult Compound = ParseCompoundStatement(Attrs);
-    // FIXME: We're dropping these statements on the floor.
+    if (Compound.isInvalid())
+      return;
+    
+    StmtResult DepResult = Actions.ActOnMSDependentExistsStmt(Result.KeywordLoc,
+                                                              Result.IsIfExists,
+                                                              Result.SS, 
+                                                              Result.Name,
+                                                              Compound.get());
+    if (DepResult.isUsable())
+      Stmts.push_back(DepResult.get());
     return;
   }
   
index c4571c96d04b6df337b725b66fc6f00746dcb6e4..2726906c1b6eeae1e1e0afebd3c609009ce1401a 100644 (file)
@@ -4665,18 +4665,18 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) {
   return MaybeCreateStmtWithCleanups(FullStmt);
 }
 
-Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
-                                                        CXXScopeSpec &SS,
-                                                        UnqualifiedId &Name) {
-  DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+Sema::IfExistsResult 
+Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
+                                   CXXScopeSpec &SS,
+                                   const DeclarationNameInfo &TargetNameInfo) {
   DeclarationName TargetName = TargetNameInfo.getName();
   if (!TargetName)
     return IER_DoesNotExist;
-
+  
   // If the name itself is dependent, then the result is dependent.
   if (TargetName.isDependentName())
     return IER_Dependent;
-      
+  
   // Do the redeclaration lookup in the current scope.
   LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName,
                  Sema::NotForRedeclaration);
@@ -4697,5 +4697,13 @@ Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
     return IER_Dependent;
   }
   
-  return IER_DoesNotExist;
+  return IER_DoesNotExist;  
 }
+
+Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
+                                                        CXXScopeSpec &SS,
+                                                        UnqualifiedId &Name) {
+  DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
+  return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
+}
+
index 5351896204ca0b0fdd00ac63f85035142b85ed34..3297c0641fe8487a83f5bd9c9af0a76f194f0416 100644 (file)
@@ -2484,3 +2484,26 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
   assert(Block);
   return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
 }
+
+StmtResult Sema::BuildMSDependentExistsStmt(SourceLocation KeywordLoc,
+                                            bool IsIfExists,
+                                            NestedNameSpecifierLoc QualifierLoc,
+                                            DeclarationNameInfo NameInfo,
+                                            Stmt *Nested)
+{
+  return new (Context) MSDependentExistsStmt(KeywordLoc, IsIfExists,
+                                             QualifierLoc, NameInfo, 
+                                             cast<CompoundStmt>(Nested));
+}
+
+
+StmtResult Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, 
+                                            bool IsIfExists,
+                                            CXXScopeSpec &SS, 
+                                            UnqualifiedId &Name,
+                                            Stmt *Nested) {
+  return BuildMSDependentExistsStmt(KeywordLoc, IsIfExists, 
+                                    SS.getWithLocInContext(Context),
+                                    GetNameFromUnqualifiedId(Name),
+                                    Nested);
+}
index b4073eb650e883351a0d4df96a45e21a868d9387..dde8a974c9847345598c97467cad13cbb8047aa2 100644 (file)
@@ -1291,7 +1291,20 @@ public:
     return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd,
                                           Cond, Inc, LoopVar, RParenLoc);
   }
-  
+
+  /// \brief Build a new C++0x range-based for statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  StmtResult RebuildMSDependentExistsStmt(SourceLocation KeywordLoc, 
+                                          bool IsIfExists,
+                                          NestedNameSpecifierLoc QualifierLoc,
+                                          DeclarationNameInfo NameInfo,
+                                          Stmt *Nested) {
+    return getSema().BuildMSDependentExistsStmt(KeywordLoc, IsIfExists,
+                                                QualifierLoc, NameInfo, Nested);
+  }
+
   /// \brief Attach body to a C++0x range-based for statement.
   ///
   /// By default, performs semantic analysis to finish the new statement.
@@ -5745,6 +5758,72 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
   return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
 }
 
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformMSDependentExistsStmt(
+                                                    MSDependentExistsStmt *S) {
+  // Transform the nested-name-specifier, if any.
+  NestedNameSpecifierLoc QualifierLoc;
+  if (S->getQualifierLoc()) {
+    QualifierLoc 
+      = getDerived().TransformNestedNameSpecifierLoc(S->getQualifierLoc());
+    if (!QualifierLoc)
+      return StmtError();
+  }
+
+  // Transform the declaration name.
+  DeclarationNameInfo NameInfo = S->getNameInfo();
+  if (NameInfo.getName()) {
+    NameInfo = getDerived().TransformDeclarationNameInfo(NameInfo);
+    if (!NameInfo.getName())
+      return StmtError();
+  }
+
+  // Check whether anything changed.
+  if (!getDerived().AlwaysRebuild() &&
+      QualifierLoc == S->getQualifierLoc() &&
+      NameInfo.getName() == S->getNameInfo().getName())
+    return S;
+  
+  // Determine whether this name exists, if we can.
+  CXXScopeSpec SS;
+  SS.Adopt(QualifierLoc);
+  bool Dependent = false;
+  switch (getSema().CheckMicrosoftIfExistsSymbol(/*S=*/0, SS, NameInfo)) {
+  case Sema::IER_Exists:
+    if (S->isIfExists())
+      break;
+      
+    return new (getSema().Context) NullStmt(S->getKeywordLoc());
+
+  case Sema::IER_DoesNotExist:
+    if (S->isIfNotExists())
+      break;
+    
+    return new (getSema().Context) NullStmt(S->getKeywordLoc());
+      
+  case Sema::IER_Dependent:
+    Dependent = true;
+    break;
+  }
+  
+  // We need to continue with the instantiation, so do so now.
+  StmtResult SubStmt = getDerived().TransformCompoundStmt(S->getSubStmt());
+  if (SubStmt.isInvalid())
+    return StmtError();
+  
+  // If we have resolved the name, just transform to the substatement.
+  if (!Dependent)
+    return SubStmt;
+  
+  // The name is still dependent, so build a dependent expression again.
+  return getDerived().RebuildMSDependentExistsStmt(S->getKeywordLoc(),
+                                                   S->isIfExists(),
+                                                   QualifierLoc,
+                                                   NameInfo,
+                                                   SubStmt.get());
+}
+
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
index 85d0f929c42bb4605634f2ba69d12c8ed8d042c8..87912af461073120668635bccaf0567e6506ba58 100644 (file)
@@ -992,6 +992,15 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   S->setBody(Reader.ReadSubStmt());
 }
 
+void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+  VisitStmt(S);
+  S->KeywordLoc = ReadSourceLocation(Record, Idx);
+  S->IsIfExists = Record[Idx++];
+  S->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
+  ReadDeclarationNameInfo(S->NameInfo, Record, Idx);
+  S->SubStmt = Reader.ReadSubStmt();
+}
+
 void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   VisitCallExpr(E);
   E->setOperator((OverloadedOperatorKind)Record[Idx++]);
@@ -1847,6 +1856,13 @@ Stmt *ASTReader::ReadStmtFromStream(Module &F) {
       S = new (Context) CXXForRangeStmt(Empty);
       break;
 
+    case STMT_MS_DEPENDENT_EXISTS:
+      S = new (Context) MSDependentExistsStmt(SourceLocation(), true,
+                                              NestedNameSpecifierLoc(),
+                                              DeclarationNameInfo(),
+                                              0);
+      break;
+        
     case EXPR_CXX_OPERATOR_CALL:
       S = new (Context) CXXOperatorCallExpr(Context, Empty);
       break;
index 463203b4a0f434fc63872bc6403cf15adc87cafc..0721c299a116f9e7dd2070e09c62305026bb5c7e 100644 (file)
@@ -957,6 +957,16 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   Code = serialization::STMT_CXX_FOR_RANGE;
 }
 
+void ASTStmtWriter::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+  VisitStmt(S);
+  Writer.AddSourceLocation(S->getKeywordLoc(), Record);
+  Record.push_back(S->isIfExists());
+  Writer.AddNestedNameSpecifierLoc(S->getQualifierLoc(), Record);
+  Writer.AddDeclarationNameInfo(S->getNameInfo(), Record);
+  Writer.AddStmt(S->getSubStmt());
+  Code = serialization::STMT_MS_DEPENDENT_EXISTS;
+}
+
 void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
   VisitCallExpr(E);
   Record.push_back(E->getOperator());
index 923293093c6ad9eada7660d1baeda4d865f32a8c..13550c793d77d5b2f0052e33682abc5d9676902b 100644 (file)
@@ -556,6 +556,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::NullStmtClass:
     case Stmt::SwitchStmtClass:
     case Stmt::WhileStmtClass:
+    case Expr::MSDependentExistsStmtClass:
       llvm_unreachable("Stmt should not be in analyzer evaluation loop");
       break;
 
diff --git a/test/Index/ms-if-exists.cpp b/test/Index/ms-if-exists.cpp
new file mode 100644 (file)
index 0000000..d1d04ee
--- /dev/null
@@ -0,0 +1,24 @@
+template<typename T>
+void f(T t) {
+  __if_exists(T::foo) {
+    { }
+    t.foo();
+  }
+
+  __if_not_exists(T::bar) {
+    int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+    { }
+  }
+}
+
+// RUN: c-index-test -test-annotate-tokens=%s:3:1:11:3 -fms-extensions %s | FileCheck %s
+
+// CHECK: Identifier: "T" [3:15 - 3:16] TypeRef=T:1:19
+// CHECK: Punctuation: "}" [4:7 - 4:8] CompoundStmt=
+// CHECK: Identifier: "t" [5:5 - 5:6] DeclRefExpr=t:2:10
+// CHECK: Punctuation: "." [5:6 - 5:7] MemberRefExpr=
+// CHECK: Identifier: "foo" [5:7 - 5:10] MemberRefExpr=
+// CHECK: Keyword: "int" [9:5 - 9:8] VarDecl=i:9:10 (Definition)
+// CHECK: Punctuation: "*" [9:9 - 9:10] VarDecl=i:9:10 (Definition)
+// CHECK: Identifier: "i" [9:10 - 9:11] VarDecl=i:9:10 (Definition)
+// CHECK: Punctuation: "=" [9:12 - 9:13] VarDecl=i:9:10 (Definition)
diff --git a/test/PCH/ms-if-exists.cpp b/test/PCH/ms-if-exists.cpp
new file mode 100644 (file)
index 0000000..4bea198
--- /dev/null
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -fms-extensions -fsyntax-only -include-pch %t %s -verify
+
+#ifndef HEADER
+#define HEADER
+template<typename T>
+void f(T t) {
+  __if_exists(T::foo) {
+    { }
+    t.foo();
+  }
+
+  __if_not_exists(T::bar) {
+    int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
+    { }
+  }
+}
+#else
+struct HasFoo { 
+  void foo();
+};
+struct HasBar { 
+  void bar(int);
+  void bar(float);
+};
+
+template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
+template void f(HasBar);
+#endif
index f22a8997b169e78f3cb1c2bbd59714e59ff5b710..129dfa7feffb32fbd3c3d44ecb267d9027d413a8 100644 (file)
@@ -44,10 +44,10 @@ void f(T t) {
   }
 
   __if_not_exists(T::bar) {
-    int *i = t;
+    int *i = t; // expected-error{{no viable conversion from 'HasFoo' to 'int *'}}
     { }
   }
 }
 
-template void f(HasFoo);
+template void f(HasFoo); // expected-note{{in instantiation of function template specialization 'f<HasFoo>' requested here}}
 template void f(HasBar);
index 4bf1c5286c48d6deff43ac3d8820033b36efb7bd..a9fd9e57d1b7a3a17a43ef2514260584bfdc2d5f 100644 (file)
@@ -1754,6 +1754,8 @@ public:
     switch (S->getStmtClass()) {
     default:
       llvm_unreachable("Unhandled Stmt");
+    case clang::Stmt::MSDependentExistsStmtClass:
+      return cast<MSDependentExistsStmt>(S)->getNameInfo();
     case Stmt::CXXDependentScopeMemberExprClass:
       return cast<CXXDependentScopeMemberExpr>(S)->getMemberNameInfo();
     case Stmt::DependentScopeDeclRefExprClass:
@@ -1788,6 +1790,7 @@ public:
   void VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
   void VisitCompoundStmt(CompoundStmt *S);
   void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { /* Do nothing. */ }
+  void VisitMSDependentExistsStmt(MSDependentExistsStmt *S);
   void VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E);
   void VisitCXXNewExpr(CXXNewExpr *E);
   void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
@@ -1897,6 +1900,14 @@ void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) {
     AddStmt(*I);
   }
 }
+void EnqueueVisitor::
+VisitMSDependentExistsStmt(MSDependentExistsStmt *S) {
+  AddStmt(S->getSubStmt());
+  AddDeclarationNameInfo(S);
+  if (NestedNameSpecifierLoc QualifierLoc = S->getQualifierLoc())
+    AddNestedNameSpecifierLoc(QualifierLoc);
+}
+
 void EnqueueVisitor::
 VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
   AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs());
index 586d9beba3b9b1b706874748157bae26b388460d..ae3aeea06c744de249b00c354e9115fc1192af49 100644 (file)
@@ -430,7 +430,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
     K = CXCursor_CallExpr;
     break;
       
-  case Stmt::ObjCMessageExprClass:      
+  case Stmt::ObjCMessageExprClass: {
     K = CXCursor_ObjCMessageExpr;
     int SelectorIdIndex = -1;
     // Check if cursor points to a selector id.
@@ -446,6 +446,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
     CXCursor C = { K, 0, { Parent, S, TU } };
     return getSelectorIdentifierCursor(SelectorIdIndex, C);
   }
+      
+  case Stmt::MSDependentExistsStmtClass:
+    K = CXCursor_UnexposedStmt;
+    break;
+  }
   
   CXCursor C = { K, 0, { Parent, S, TU } };
   return C;