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
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index daaa354..5b1654c 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -305,6 +305,22 @@
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 214378a..93b2f65 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -182,6 +182,13 @@
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 c56931b..6f020cc 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -73,6 +73,7 @@
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 5c2ed4e..fb88434 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -2152,7 +2152,16 @@
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 c4571c9..2726906 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -4665,18 +4665,18 @@
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 @@
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 5351896..3297c06 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2484,3 +2484,26 @@
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 b4073eb..dde8a97 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1291,7 +1291,20 @@
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 @@
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 85d0f92..87912af 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -992,6 +992,15 @@
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 @@
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 463203b..0721c29 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -957,6 +957,16 @@
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 9232930..13550c7 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -556,6 +556,7 @@
case Stmt::NullStmtClass:
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
+ case Expr::MSDependentExistsStmtClass:
llvm_unreachable("Stmt should not be in analyzer evaluation loop");
break;