]> granicus.if.org Git - clang/commitdiff
[MSVC] Late parsing of in-class defined member functions in template
authorAlexey Bataev <a.bataev@hotmail.com>
Wed, 15 Jun 2016 11:19:39 +0000 (11:19 +0000)
committerAlexey Bataev <a.bataev@hotmail.com>
Wed, 15 Jun 2016 11:19:39 +0000 (11:19 +0000)
classes.

MSVC actively uses unqualified lookup in dependent bases, lookup at the
instantiation point (non-dependent names may be resolved on things
declared later) etc. and all this stuff is the main cause of
incompatibility between clang and MSVC.

Clang tries to emulate MSVC behavior but it may fail in many cases.
clang could store lexed tokens for member functions definitions within
ClassTemplateDecl for later parsing during template instantiation.

It will allow resolving many possible issues with lookup in dependent
base classes and removing many already existing MSVC-specific
hacks/workarounds from the clang code.

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

22 files changed:
include/clang-c/Index.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/StmtCXX.h
include/clang/Basic/StmtNodes.td
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/StmtCXX.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGStmt.cpp
lib/Parse/ParseTemplate.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/SemaTemplate/ms-lookup-template-base-classes.cpp
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index 89612b9c93a95843cdea5c98fa18d407a67b445c..5fb1b2c5c0461fcf5ae3d4076f4005b9450db4f4 100644 (file)
@@ -2305,7 +2305,11 @@ enum CXCursorKind {
    */
   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.
index 1693976cf852a15e7f33c8c4ba104790f17058a5..bc727c7433f53ba99c444e5077276bd59738ddf9 100644 (file)
@@ -2332,6 +2332,7 @@ DEF_TRAVERSE_STMT(SEHExceptStmt, {})
 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, {})
index 1d29c228a4b3c7eb5ac0ea760cccd2eb2cf8ea5e..6c705cf596d1608927a0ecfe4415cb02a2827ccd 100644 (file)
@@ -18,6 +18,7 @@
 #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 {
@@ -417,6 +418,51 @@ public:
   }
 };
 
+/// 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
index b4f3937d5835f6f48cc6f89a92e015b4148107b2..b7a88f3885b424f31102da5b93cfbd5147d83072 100644 (file)
@@ -187,6 +187,7 @@ def SEHExceptStmt : Stmt;
 def SEHFinallyStmt : Stmt;
 def SEHLeaveStmt : Stmt;
 def MSDependentExistsStmt : Stmt;
+def MSLateParsedCompoundStmt : Stmt;
 
 // OpenCL Extensions.
 def AsTypeExpr : DStmt<Expr>;
index 9cbad6b634dab90abe8bf51e2b84bfd97cb2f511..62b0926b54389c1ac5b0e614c6fcceb0bfb3b2a1 100644 (file)
@@ -1181,9 +1181,11 @@ private:
 
   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);
index 9583dd5b268e45f6d52b5c3ad03d1da92eb9ce5f..f1f97ffa5200add9ff6ada903c2b2f5e3f4b435c 100644 (file)
@@ -3507,6 +3507,11 @@ public:
   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,
index eb9ac238aa59b509ddc344746aba852750203a2f..5e8abc0e6fdde91534e7c0e5836c6b15294a7991 100644 (file)
@@ -1220,6 +1220,8 @@ namespace clang {
       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.
index 4692db84b505d8b09d840b300a3b7509485e6805..08cdd2045820cbd535d624f0dec34accfc6e4761 100644 (file)
@@ -86,3 +86,38 @@ VarDecl *CXXForRangeStmt::getLoopVariable() {
 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);
+}
+
index 2e15c81cccd7e6de30b7a332818ab46000cf328b..07aef87f5fba96b054c25d0af4b83b439dd2ab11 100644 (file)
@@ -2352,6 +2352,10 @@ void StmtPrinter::VisitCoreturnStmt(CoreturnStmt *S) {
   OS << ";";
 }
 
+void StmtPrinter::VisitMSLateParsedCompoundStmt(MSLateParsedCompoundStmt *S) {
+  OS << S->getStringRepresentation();
+}
+
 void StmtPrinter::VisitCoawaitExpr(CoawaitExpr *S) {
   OS << "co_await ";
   PrintExpr(S->getOperand());
index f68bc3a397f778d84eda9ab64f82422456a18232..4868beccb7a02b73f51aa79dc0995bdeb9f016ae 100644 (file)
@@ -1499,6 +1499,11 @@ void StmtProfiler::VisitCoreturnStmt(const CoreturnStmt *S) {
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitMSLateParsedCompoundStmt(
+    const MSLateParsedCompoundStmt *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitCoawaitExpr(const CoawaitExpr *S) {
   VisitExpr(S);
 }
index ff70bbc866f478cf889f6b638d8a38279008054e..dfabd2e8d1377def0ce6407feffca58407c3eb63 100644 (file)
@@ -80,6 +80,7 @@ void CodeGenFunction::EmitStmt(const Stmt *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:
index 6cf7b6d3dc55430b0872b72720c10af887de80f9..0369aae5597b8f3457cc4cf66a1055c238a5a7d7 100644 (file)
@@ -1417,6 +1417,90 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
     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();
index 9ed2d72fcd9d081abea655fe0d6a4ff774133dc1..b8f68c03bd41f85f8c178120b81ccb0f67914fdc 100644 (file)
@@ -89,6 +89,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
   PP.addCommentHandler(CommentSemaHandler.get());
 
   PP.setCodeCompletionHandler(*this);
+  if (getLangOpts().MSVCCompat)
+    Actions.SetLateTemplateParser(LateTemplateParserCallback, nullptr, this);
 }
 
 DiagnosticBuilder Parser::Diag(SourceLocation Loc, unsigned DiagID) {
@@ -1053,12 +1055,35 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
       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();
 
index 6f23115f02a897a9f06afbc70a2ef0d5c73f6043..098a76379b31b5c5205d4cf8c7180296419de720 100644 (file)
@@ -2213,11 +2213,11 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
   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)
index d2d4098d17709e2ed235f9bf498422213c0d71c1..51ae9c1b84400367be619b1b9a7aab6261cb2a6b 100644 (file)
@@ -3978,3 +3978,30 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
 
   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();
+}
index bba90191019c715559a0f8256fec578a254f486b..985f3072ef9db848660edecdd6de041a1c26d9cb 100644 (file)
@@ -1292,6 +1292,17 @@ public:
                                     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.
@@ -6606,6 +6617,16 @@ TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) {
                                        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>
index 15e289f6f8e2e1de0c788f3725c3ee97a1a488ef..578193c9eeb80a564252434f913e850f5ced0b84 100644 (file)
@@ -382,6 +382,21 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) {
                 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");
@@ -2867,6 +2882,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
       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]);
index 5382b4af9228476cab867ea7c74ee0301cfe1806..942485f209cf0ba4682303951ff30e3c73d781e9 100644 (file)
@@ -297,6 +297,18 @@ void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) {
   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");
index 84515022fc0f9ba9cd7208d5d60fc208aa42a469..8df4c0ff85276d124497bd4e84ea32e77976d069 100644 (file)
@@ -808,6 +808,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
     case Stmt::SwitchStmtClass:
     case Stmt::WhileStmtClass:
     case Expr::MSDependentExistsStmtClass:
+    case Expr::MSLateParsedCompoundStmtClass:
     case Stmt::CapturedStmtClass:
     case Stmt::OMPParallelDirectiveClass:
     case Stmt::OMPSimdDirectiveClass:
index 6afc7091260dcde091f6c41686d97db701638643..71b7eb4b301600998c71573e26f229f488300567 100644 (file)
@@ -556,6 +556,7 @@ struct Base {
 template <typename T> struct Template : T {
   void member() {
     f(); // expected-warning {{found via unqualified lookup into dependent bases}}
+    T::f();
   }
 };
 void test() {
index 4a1badb68d52403fdfae304e9f093bd1f1291677..d412f80e97af7032606c8ca5cfc620d38801efe2 100644 (file)
@@ -4632,6 +4632,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
       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:
index 075ff291d13acf1104f79e7e225080d4b739d822..a718af37ea116b16673d8dcf251f98a66007a084 100644 (file)
@@ -168,6 +168,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
     K = CXCursor_MSAsmStmt;
     break;
   
+  case Stmt::MSLateParsedCompoundStmtClass:
+    K = CXCursor_MSLateParsedCompoundStmt;
+    break;
+  
   case Stmt::ObjCAtTryStmtClass:
     K = CXCursor_ObjCAtTryStmt;
     break;