*/
CXCursor_OMPTargetUpdateDirective = 265,
- CXCursor_LastStmt = CXCursor_OMPTargetUpdateDirective,
+ /** \brief A MS-specific late parsed compound statement.
+ */
+ CXCursor_MSLateParsedCompoundStmt = 266,
+
+ CXCursor_LastStmt = CXCursor_MSLateParsedCompoundStmt,
/**
* \brief Cursor that represents the translation unit itself.
DEF_TRAVERSE_STMT(SEHFinallyStmt, {})
DEF_TRAVERSE_STMT(SEHLeaveStmt, {})
DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
+DEF_TRAVERSE_STMT(MSLateParsedCompoundStmt, {})
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
DEF_TRAVERSE_STMT(OpaqueValueExpr, {})
#include "clang/AST/Expr.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/Stmt.h"
+#include "clang/Lex/Token.h"
#include "llvm/Support/Compiler.h"
namespace clang {
}
};
+/// This represents a group of statements like { stmt stmt } that must be parsed
+/// only during instantiation. Required for better MSVC compatibility.
+class MSLateParsedCompoundStmt final
+ : public Stmt,
+ private llvm::TrailingObjects<MSLateParsedCompoundStmt, Token> {
+ friend class TrailingObjects;
+ friend class ASTStmtReader;
+ SourceLocation LBraceLoc, RBraceLoc;
+ StringRef StringRep;
+ unsigned NumToks;
+
+ MSLateParsedCompoundStmt()
+ : Stmt(MSLateParsedCompoundStmtClass), NumToks(0) {}
+
+ /// Set tokens for the statement.
+ void init(ASTContext &C, SourceLocation LB, SourceLocation RB,
+ ArrayRef<Token> Tokens, StringRef Rep);
+
+public:
+ static MSLateParsedCompoundStmt *Create(ASTContext &C, SourceLocation LB,
+ SourceLocation RB,
+ ArrayRef<Token> Tokens,
+ StringRef Rep);
+ /// Build an empty statement.
+ static MSLateParsedCompoundStmt *CreateEmpty(ASTContext &C,
+ unsigned NumTokens);
+
+ SourceLocation getLocStart() const LLVM_READONLY { return LBraceLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return RBraceLoc; }
+
+ /// Returns representation of the statement as a string.
+ StringRef getStringRepresentation() const { return StringRep; }
+
+ /// Get list of tokens associated with the statement.
+ ArrayRef<Token> tokens() const;
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ static bool classof(const Stmt *S) {
+ return S->getStmtClass() == MSLateParsedCompoundStmtClass;
+ }
+};
+
} // end namespace clang
#endif
def SEHFinallyStmt : Stmt;
def SEHLeaveStmt : Stmt;
def MSDependentExistsStmt : Stmt;
+def MSLateParsedCompoundStmt : Stmt;
// OpenCL Extensions.
def AsTypeExpr : DStmt<Expr>;
void LexTemplateFunctionForLateParsing(CachedTokens &Toks);
void ParseLateTemplatedFuncDef(LateParsedTemplate &LPT);
+ void ParseMSVCTemplatedFuncDef(LateParsedTemplate &LPT);
static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT);
static void LateTemplateParserCleanupCallback(void *P);
+ static void MSVCTemplateParserCallback(void *P, LateParsedTemplate &LPT);
Sema::ParsingClassState
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName,
SourceLocation Location,
bool AlwaysCreate);
+ /// Builds late parsed compound statement or just compound statement in MSVC
+ /// compatibility mode.
+ StmtResult ActOnMSLateParsedCompoundStmt(SourceLocation LB, SourceLocation RB,
+ ArrayRef<Token> Tokens,
+ StringRef Rep);
VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType,
SourceLocation StartLoc,
STMT_GCCASM,
/// \brief A MS-style AsmStmt record.
STMT_MSASM,
+ /// \brief A MS-specific late parsed compound statement.
+ STMT_MS_LATE_PARSED_COMPOUND,
/// \brief A PredefinedExpr record.
EXPR_PREDEFINED,
/// \brief A DeclRefExpr record.
const VarDecl *CXXForRangeStmt::getLoopVariable() const {
return const_cast<CXXForRangeStmt *>(this)->getLoopVariable();
}
+
+MSLateParsedCompoundStmt *
+MSLateParsedCompoundStmt::Create(ASTContext &C, SourceLocation LB,
+ SourceLocation RB, ArrayRef<Token> Tokens,
+ StringRef Rep) {
+ // Allocate space for private variables and initializer expressions.
+ void *Mem = C.Allocate(totalSizeToAlloc<Token>(Tokens.size()),
+ llvm::alignOf<MSLateParsedCompoundStmt>());
+ auto *S = new (Mem) MSLateParsedCompoundStmt();
+ S->init(C, LB, RB, Tokens, Rep);
+ return S;
+}
+
+MSLateParsedCompoundStmt *
+MSLateParsedCompoundStmt::CreateEmpty(ASTContext &C, unsigned NumTokens) {
+ // Allocate space for private variables and initializer expressions.
+ void *Mem = C.Allocate(totalSizeToAlloc<Token>(NumTokens),
+ llvm::alignOf<MSLateParsedCompoundStmt>());
+ return new (Mem) MSLateParsedCompoundStmt();
+}
+
+void MSLateParsedCompoundStmt::init(ASTContext &C, SourceLocation LB,
+ SourceLocation RB, ArrayRef<Token> Tokens,
+ StringRef Rep) {
+ LBraceLoc = LB;
+ RBraceLoc = RB;
+ std::copy(Tokens.begin(), Tokens.end(), getTrailingObjects<Token>());
+ StringRep = Rep.copy(C);
+ NumToks = Tokens.size();
+}
+
+ArrayRef<Token> MSLateParsedCompoundStmt::tokens() const {
+ return llvm::makeArrayRef(getTrailingObjects<Token>(), NumToks);
+}
+
OS << ";";
}
+void StmtPrinter::VisitMSLateParsedCompoundStmt(MSLateParsedCompoundStmt *S) {
+ OS << S->getStringRepresentation();
+}
+
void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
OS << "co_await ";
PrintExpr(S->getOperand());
VisitStmt(S);
}
+void StmtProfiler::VisitMSLateParsedCompoundStmt(
+ const MSLateParsedCompoundStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) {
VisitExpr(S);
}
case Stmt::SEHExceptStmtClass:
case Stmt::SEHFinallyStmtClass:
case Stmt::MSDependentExistsStmtClass:
+ case Stmt::MSLateParsedCompoundStmtClass:
llvm_unreachable("invalid statement class to emit generically");
case Stmt::NullStmtClass:
case Stmt::CompoundStmtClass:
delete *I;
}
+void Parser::MSVCTemplateParserCallback(void *P, LateParsedTemplate &LPT) {
+ ((Parser *)P)->ParseMSVCTemplatedFuncDef(LPT);
+}
+
+/// \brief Late parse a C++ function template in Microsoft mode.
+void Parser::ParseMSVCTemplatedFuncDef(LateParsedTemplate &LPT) {
+ if (!LPT.D)
+ return;
+
+ // Get the FunctionDecl.
+ FunctionDecl *FunD = LPT.D->getAsFunction();
+ // Track template parameter depth.
+ TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
+
+ SmallVector<ParseScope*, 4> TemplateParamScopeStack;
+
+ // Get the list of DeclContexts to reenter.
+ SmallVector<DeclContext*, 4> DeclContextsToReenter;
+ DeclContext *DD = FunD;
+ while (DD && !DD->isTranslationUnit()) {
+ DeclContextsToReenter.push_back(DD);
+ DD = DD->getLexicalParent();
+ }
+
+ // Reenter template scopes from outermost to innermost.
+ SmallVectorImpl<DeclContext *>::reverse_iterator II =
+ DeclContextsToReenter.rbegin();
+ for (; II != DeclContextsToReenter.rend(); ++II) {
+ TemplateParamScopeStack.push_back(new ParseScope(this,
+ Scope::TemplateParamScope));
+ unsigned NumParamLists =
+ Actions.ActOnReenterTemplateScope(getCurScope(), cast<Decl>(*II));
+ CurTemplateDepthTracker.addDepth(NumParamLists);
+ if (*II != FunD) {
+ TemplateParamScopeStack.push_back(new ParseScope(this, Scope::DeclScope));
+ Actions.PushDeclContext(Actions.getCurScope(), *II);
+ }
+ }
+
+ assert(!LPT.Toks.empty() && "Empty body!");
+
+ // Append the current token at the end of the new token stream so that it
+ // doesn't get lost.
+ LPT.Toks.push_back(Tok);
+ PP.EnterTokenStream(LPT.Toks, true);
+
+ // Consume the previously pushed token.
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+ assert(Tok.isOneOf(tok::l_brace, tok::colon, tok::kw_try) &&
+ "Inline method not starting with '{', ':' or 'try'");
+
+ // Parse the method body. Function body parsing code is similar enough
+ // to be re-used for method bodies as well.
+ ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
+
+ if (Tok.is(tok::kw_try)) {
+ ParseFunctionTryBlock(LPT.D, FnScope);
+ } else {
+ if (Tok.is(tok::colon))
+ ParseConstructorInitializer(LPT.D);
+ else
+ Actions.ActOnDefaultCtorInitializers(LPT.D);
+
+ if (Tok.is(tok::l_brace)) {
+ assert((!isa<FunctionTemplateDecl>(LPT.D) ||
+ cast<FunctionTemplateDecl>(LPT.D)
+ ->getTemplateParameters()
+ ->getDepth() == TemplateParameterDepth - 1) &&
+ "TemplateParameterDepth should be greater than the depth of "
+ "current template being instantiated!");
+ ParseFunctionStatementBody(LPT.D, FnScope);
+ Actions.UnmarkAsLateParsedTemplate(FunD);
+ } else
+ Actions.ActOnFinishFunctionBody(LPT.D, nullptr);
+ }
+
+ // Exit scopes.
+ FnScope.Exit();
+ SmallVectorImpl<ParseScope *>::reverse_iterator I =
+ TemplateParamScopeStack.rbegin();
+ for (; I != TemplateParamScopeStack.rend(); ++I)
+ delete *I;
+}
+
/// \brief Lex a delayed template function for late parsing.
void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) {
tok::TokenKind kind = Tok.getKind();
PP.addCommentHandler(CommentSemaHandler.get());
PP.setCodeCompletionHandler(*this);
+ if (getLangOpts().MSVCCompat)
+ Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr, this);
}
DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
Actions.MarkAsLateParsedTemplate(FnD, DP, Toks);
}
return DP;
- }
- else if (CurParsedObjCImpl &&
- !TemplateInfo.TemplateParams &&
- (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
- Tok.is(tok::colon)) &&
- Actions.CurContext->isTranslationUnit()) {
+ } else if (getLangOpts().MSVCCompat && Tok.isNot(tok::equal) &&
+ TemplateInfo.Kind == ParsedTemplateInfo::Template &&
+ Actions.canDelayFunctionBody(D)) {
+ // In delayed template parsing mode, for function template we consume the
+ // tokens and store them for late parsing at the end of the translation
+ // unit.
+ MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
+
+ ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope);
+
+ CachedTokens Toks;
+ LexTemplateFunctionForLateParsing(Toks);
+
+ Decl *Res = Actions.ActOnStartOfFunctionDef(getCurScope(), D,
+ *TemplateInfo.TemplateParams);
+ D.complete(Res);
+ D.getMutableDeclSpec().abort();
+ StmtResult Body = Actions.ActOnMSLateParsedCompoundStmt(
+ Toks.begin()->getLocation(), Tok.getLocation(), Toks,
+ Lexer::getSourceText(
+ {{Toks.begin()->getLocation(), Tok.getLocation()}, false},
+ Actions.getASTContext().getSourceManager(), getLangOpts()));
+ BodyScope.Exit();
+
+ return Actions.ActOnFinishFunctionBody(Res, Body.get());
+ } else if (CurParsedObjCImpl && !TemplateInfo.TemplateParams &&
+ (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) ||
+ Tok.is(tok::colon)) &&
+ Actions.CurContext->isTranslationUnit()) {
ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope);
Scope *ParentScope = getCurScope()->getParent();
bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen);
if (R.empty() && !ADL) {
- if (SS.isEmpty() && getLangOpts().MSVCCompat) {
- if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo,
- TemplateKWLoc, TemplateArgs))
- return E;
- }
+ // if (SS.isEmpty() && getLangOpts().MSVCCompat) {
+ // if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo,
+ // TemplateKWLoc, TemplateArgs))
+ // return E;
+ // }
// Don't diagnose an empty lookup for inline assembly.
if (IsInlineAsmIdentifier)
return Res;
}
+
+StmtResult Sema::ActOnMSLateParsedCompoundStmt(SourceLocation LB,
+ SourceLocation RB,
+ ArrayRef<Token> Tokens,
+ StringRef Rep) {
+ if (CurContext->isDependentContext())
+ return MSLateParsedCompoundStmt::Create(getASTContext(), LB, RB, Tokens,
+ Rep);
+
+ QualType CXXThisTy = getCurrentThisType();
+ assert(!CXXThisTy.isNull());
+ auto *CXXThisRD = CXXThisTy->castAs<PointerType>()
+ ->getPointeeCXXRecordDecl()
+ ->getCanonicalDecl();
+ DeclContext *DC = getFunctionLevelDeclContext();
+ while (auto *PCXXRD = dyn_cast<CXXRecordDecl>(DC)) {
+ if (PCXXRD->getCanonicalDecl() == CXXThisRD)
+ break;
+ DC = DC->getParent();
+ }
+ auto *MD = dyn_cast<CXXMethodDecl>(DC);
+ LateParsedTemplate LPT;
+ LPT.Toks.append(Tokens.begin(), Tokens.end());
+ LPT.D = MD;
+ LateTemplateParser(OpaqueParser, LPT);
+ return MD->getBody();
+}
Constraints, Clobbers, Exprs, EndLoc);
}
+ /// Build a new compound statement.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ StmtResult RebuildMSLateParsedCompoundStmt(SourceLocation LB,
+ SourceLocation RB,
+ ArrayRef<Token> Tokens,
+ StringRef Rep) {
+ return getSema().ActOnMSLateParsedCompoundStmt(LB, RB, Tokens, Rep);
+ }
+
/// \brief Build a new co_return statement.
///
/// By default, performs semantic analysis to build the new statement.
TransformedExprs, S->getEndLoc());
}
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformMSLateParsedCompoundStmt(
+ MSLateParsedCompoundStmt *S) {
+ if (SemaRef.CurContext->isDependentContext())
+ return S;
+ return getDerived().RebuildMSLateParsedCompoundStmt(
+ S->getLocStart(), S->getLocEnd(), S->tokens(),
+ S->getStringRepresentation());
+}
+
// C++ Coroutines TS
template<typename Derived>
Constraints, Exprs, Clobbers);
}
+void ASTStmtReader::VisitMSLateParsedCompoundStmt(MSLateParsedCompoundStmt *S) {
+ VisitStmt(S);
+ SourceLocation LB = ReadSourceLocation(Record, Idx);
+ SourceLocation RB = ReadSourceLocation(Record, Idx);
+ std::string StringRep = ReadString(Record, Idx);
+ unsigned NumToks = Record[Idx++];
+
+ // Read the tokens.
+ SmallVector<Token, 16> Toks;
+ Toks.reserve(NumToks);
+ for (unsigned I = 0, E = NumToks; I != E; ++I)
+ Toks.push_back(ReadToken(Record, Idx));
+ S->init(Reader.getContext(), LB, RB, Toks, StringRep);
+}
+
void ASTStmtReader::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
// FIXME: Implement coroutine serialization.
llvm_unreachable("unimplemented");
S = new (Context) MSAsmStmt(Empty);
break;
+ case STMT_MS_LATE_PARSED_COMPOUND:
+ S = MSLateParsedCompoundStmt::CreateEmpty(
+ Context, Record[ASTStmtReader::NumStmtFields]);
+ break;
+
case STMT_CAPTURED:
S = CapturedStmt::CreateDeserialized(Context,
Record[ASTStmtReader::NumStmtFields]);
Code = serialization::STMT_MSASM;
}
+void ASTStmtWriter::VisitMSLateParsedCompoundStmt(MSLateParsedCompoundStmt *S) {
+ VisitStmt(S);
+ Record.push_back(S->tokens().size());
+ Record.AddSourceLocation(S->getLocStart());
+ Record.AddSourceLocation(S->getLocEnd());
+ Record.AddString(S->getStringRepresentation());
+ for (auto &Tok : S->tokens())
+ Writer.AddToken(Tok, Record.getRecordData());
+
+ Code = serialization::STMT_MS_LATE_PARSED_COMPOUND;
+}
+
void ASTStmtWriter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
// FIXME: Implement coroutine serialization.
llvm_unreachable("unimplemented");
case Stmt::SwitchStmtClass:
case Stmt::WhileStmtClass:
case Expr::MSDependentExistsStmtClass:
+ case Expr::MSLateParsedCompoundStmtClass:
case Stmt::CapturedStmtClass:
case Stmt::OMPParallelDirectiveClass:
case Stmt::OMPSimdDirectiveClass:
template <typename T> struct Template : T {
void member() {
f(); // expected-warning {{found via unqualified lookup into dependent bases}}
+ T::f();
}
};
void test() {
return cxstring::createRef("GCCAsmStmt");
case CXCursor_MSAsmStmt:
return cxstring::createRef("MSAsmStmt");
+ case CXCursor_MSLateParsedCompoundStmt:
+ return cxstring::createRef("MSLateParsedCompoundStmt");
case CXCursor_ObjCAtTryStmt:
return cxstring::createRef("ObjCAtTryStmt");
case CXCursor_ObjCAtCatchStmt:
K = CXCursor_MSAsmStmt;
break;
+ case Stmt::MSLateParsedCompoundStmtClass:
+ K = CXCursor_MSLateParsedCompoundStmt;
+ break;
+
case Stmt::ObjCAtTryStmtClass:
K = CXCursor_ObjCAtTryStmt;
break;