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". llvm-svn: 142901
This commit is contained in:
parent
4223b3b380
commit
deb4a2be67
|
@ -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, { })
|
||||
|
|
|
@ -1596,7 +1596,6 @@ public:
|
|||
}
|
||||
|
||||
static bool classof(SEHTryStmt *) { return true; }
|
||||
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -2603,9 +2603,23 @@ public:
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -4665,10 +4665,10 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) {
|
|||
return MaybeCreateStmtWithCleanups(FullStmt);
|
||||
}
|
||||
|
||||
Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
|
||||
Sema::IfExistsResult
|
||||
Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
|
||||
CXXScopeSpec &SS,
|
||||
UnqualifiedId &Name) {
|
||||
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
|
||||
const DeclarationNameInfo &TargetNameInfo) {
|
||||
DeclarationName TargetName = TargetNameInfo.getName();
|
||||
if (!TargetName)
|
||||
return IER_DoesNotExist;
|
||||
|
@ -4699,3 +4699,11 @@ Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
|
|||
|
||||
return IER_DoesNotExist;
|
||||
}
|
||||
|
||||
Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S,
|
||||
CXXScopeSpec &SS,
|
||||
UnqualifiedId &Name) {
|
||||
DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name);
|
||||
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1292,6 +1292,19 @@ public:
|
|||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
@ -447,6 +447,11 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, CXTranslationUnit TU,
|
|||
return getSelectorIdentifierCursor(SelectorIdIndex, C);
|
||||
}
|
||||
|
||||
case Stmt::MSDependentExistsStmtClass:
|
||||
K = CXCursor_UnexposedStmt;
|
||||
break;
|
||||
}
|
||||
|
||||
CXCursor C = { K, 0, { Parent, S, TU } };
|
||||
return C;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue