diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-10-25 01:33:02 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-10-25 01:33:02 +0000 |
commit | ba0513de93d2fab6db5ab30b6927209fcc883078 (patch) | |
tree | 75067afaf5c45f10ab9a9647d6a372ddd925e4a1 | |
parent | f11e923433b62efb0fbaeb2573e8457f1c4a1b1e (diff) |
Implement support for dependent Microsoft __if_exists/__if_not_exists
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
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 3 | ||||
-rw-r--r-- | include/clang/AST/Stmt.h | 3 | ||||
-rw-r--r-- | include/clang/AST/StmtCXX.h | 85 | ||||
-rw-r--r-- | include/clang/Basic/StmtNodes.td | 1 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 16 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 4 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 16 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGStmt.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 81 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 16 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 10 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 | ||||
-rw-r--r-- | test/Index/ms-if-exists.cpp | 24 | ||||
-rw-r--r-- | test/PCH/ms-if-exists.cpp | 29 | ||||
-rw-r--r-- | test/SemaTemplate/ms-if-exists.cpp | 4 | ||||
-rw-r--r-- | tools/libclang/CIndex.cpp | 11 | ||||
-rw-r--r-- | tools/libclang/CXCursor.cpp | 7 |
21 files changed, 359 insertions, 16 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 0ec09c9b09..a47f7008a2 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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, { }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 2a6fd6bc96..8840719413 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -1596,9 +1596,8 @@ public: } static bool classof(SEHTryStmt *) { return true; } - }; - + } // end namespace clang #endif diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 42dcf2bb7b..056a0a393c 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -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 diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 7b3d7762c2..02aec8cfef 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -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>; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 22a308dd2a..f3634f1c11 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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 diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 49f1ddfa26..d237f1b634 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -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 diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index daaa354ac3..5b1654c924 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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"; } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 214378a974..93b2f65818 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -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); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index c56931bbc6..6f020ccab0 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -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: diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 5c2ed4e5f5..fb88434929 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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; } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c4571c96d0..2726906c1b 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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); +} + diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 5351896204..3297c0641f 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index b4073eb650..dde8a974c9 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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. @@ -5747,6 +5760,72 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { 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) { StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock()); if(TryBlock.isInvalid()) return StmtError(); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 85d0f929c4..87912af461 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -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; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 463203b4a0..0721c299a1 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -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()); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 923293093c..13550c793d 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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 index 0000000000..d1d04ee7f1 --- /dev/null +++ b/test/Index/ms-if-exists.cpp @@ -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 index 0000000000..4bea198d9b --- /dev/null +++ b/test/PCH/ms-if-exists.cpp @@ -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 diff --git a/test/SemaTemplate/ms-if-exists.cpp b/test/SemaTemplate/ms-if-exists.cpp index f22a8997b1..129dfa7fef 100644 --- a/test/SemaTemplate/ms-if-exists.cpp +++ b/test/SemaTemplate/ms-if-exists.cpp @@ -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); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 4bf1c5286c..a9fd9e57d1 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -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); @@ -1898,6 +1901,14 @@ void EnqueueVisitor::VisitCompoundStmt(CompoundStmt *S) { } } 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()); AddDeclarationNameInfo(E); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 586d9beba3..ae3aeea06c 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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; |