Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -569,6 +569,8 @@ OpaqueParser = P; } + FunctionDecl *MSVCInstantiation = nullptr; + class DelayedDiagnostics; class DelayedDiagnosticsState { @@ -3799,6 +3801,7 @@ IdentifierInfo *II, bool AllowBuiltinCreation=false); + void MSVCMakeFakeCXXScopeSpec(LookupResult &R, CXXScopeSpec &SS) const; ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, @@ -9661,7 +9664,7 @@ struct LateParsedTemplate { CachedTokens Toks; /// \brief The template function declaration to be late parsed. - Decl *D; + Decl *D = nullptr; }; } // end namespace clang Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -943,6 +943,11 @@ // context is dependent. if (cast(this)->getFriendObjectKind()) return getLexicalParent()->isDependentContext(); + + const LangOptions &LO = getParentASTContext().getLangOpts(); + if (LO.DelayedTemplateParsing && LO.MSVCCompat && + Function->isLateTemplateParsed()) + return true; } // FIXME: A variable template is a dependent context, but is not a @@ -1329,9 +1334,14 @@ // from being visible? if (isa(D)) return true; - if (FunctionDecl *FD = dyn_cast(D)) + if (FunctionDecl *FD = dyn_cast(D)) { if (FD->isFunctionTemplateSpecialization()) return true; + const LangOptions &LO = FD->getASTContext().getLangOpts(); + if (LO.DelayedTemplateParsing && LO.MSVCCompat && + FD->isLateTemplateParsed() && FD->isImplicit()) + return true; + } return false; } Index: lib/Parse/ParseTemplate.cpp =================================================================== --- lib/Parse/ParseTemplate.cpp +++ lib/Parse/ParseTemplate.cpp @@ -1403,7 +1403,8 @@ "TemplateParameterDepth should be greater than the depth of " "current template being instantiated!"); ParseFunctionStatementBody(LPT.D, FnScope); - Actions.UnmarkAsLateParsedTemplate(FunD); + if (!getLangOpts().MSVCCompat) + Actions.UnmarkAsLateParsedTemplate(FunD); } else Actions.ActOnFinishFunctionBody(LPT.D, nullptr); } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -321,9 +321,11 @@ // Perform unqualified name lookup. LookupName(Result, S); + // Use workaround only in non-instantiation mode. // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. - if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) { + if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty()) && + !MSVCInstantiation) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, II, NameLoc)) return TypeInBase; @@ -788,9 +790,11 @@ LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); + // Use workaround only in non-instantiation mode // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. - if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) { + if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat && + !MSVCInstantiation) { if (ParsedType TypeInBase = recoverFromTypeInKnownDependentBase(*this, *Name, NameLoc)) return TypeInBase; @@ -930,6 +934,8 @@ // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. + if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation) + MSVCMakeFakeCXXScopeSpec(Result, SS); return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, IsAddressOfOperand, /*TemplateArgs=*/nullptr); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -1900,11 +1900,10 @@ bool isInstance = CurMethod && CurMethod->isInstance() && DC == CurMethod->getParent() && !isDefaultArgument; - // Give a code modification hint to insert 'this->'. // TODO: fixit for inserting 'Base::' in the other cases. // Actually quite difficult! - if (getLangOpts().MSVCCompat) + if (getLangOpts().MSVCCompat && !MSVCInstantiation) diagnostic = diag::ext_found_via_dependent_bases_lookup; if (isInstance) { Diag(R.getNameLoc(), diagnostic) << Name @@ -2108,6 +2107,19 @@ TemplateArgs); } +void Sema::MSVCMakeFakeCXXScopeSpec(LookupResult &R, CXXScopeSpec &SS) const { + assert(SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation); + if (R.getNamingClass() && + R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) { + // Synthesize a fake NNS that points to the derived class. This will + // perform name lookup during template instantiation. + auto *NNS = NestedNameSpecifier::Create( + getASTContext(), nullptr, true, R.getNamingClass()->getTypeForDecl()); + SourceLocation Loc = R.getNameLoc(); + SS.MakeTrivial(getASTContext(), NNS, SourceRange(Loc, Loc)); + } +} + ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, @@ -2171,20 +2183,26 @@ bool MemberOfUnknownSpecialization; LookupTemplateName(R, S, SS, QualType(), /*EnteringContext=*/false, MemberOfUnknownSpecialization); - + if (MemberOfUnknownSpecialization || - (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) + (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation)) { + if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation) + MSVCMakeFakeCXXScopeSpec(R, SS); return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); + } } else { bool IvarLookupFollowUp = II && !SS.isSet() && getCurMethodDecl(); LookupParsedName(R, S, &SS, !IvarLookupFollowUp); // If the result might be in a dependent base class, this is a dependent // id-expression. - if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) + if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) { + if (SS.isEmpty() && getLangOpts().MSVCCompat && MSVCInstantiation) + MSVCMakeFakeCXXScopeSpec(R, SS); return ActOnDependentIdExpression(SS, TemplateKWLoc, NameInfo, IsAddressOfOperand, TemplateArgs); + } // If this reference is in an Objective-C method, then we need to do // some special Objective-C lookup, too. @@ -2213,7 +2231,7 @@ bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { - if (SS.isEmpty() && getLangOpts().MSVCCompat) { + if (SS.isEmpty() && getLangOpts().MSVCCompat && !MSVCInstantiation) { if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo, TemplateKWLoc, TemplateArgs)) return E; Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -1027,6 +1027,48 @@ }; } // end anonymous namespace +static DeclContext *GetMSVCInstantiationContext(Sema &S, DeclContext *Ctx) { + assert(S.getLangOpts().MSVCCompat && S.MSVCInstantiation); + if (auto *RD = dyn_cast(Ctx)) { + for (DeclContext *C = S.MSVCInstantiation; C && !C->isTranslationUnit(); + C = C->getLookupParent()) { + if (auto *InstRD = dyn_cast(C)) + if (isTemplateInstantiation(InstRD->getTemplateSpecializationKind()) && + RD->Equals(InstRD->getTemplateInstantiationPattern())) + return C; + } + } + return nullptr; +} + +static bool isBaseClass(const CXXRecordDecl *Record, CXXRecordDecl *Base) { + SmallVector Queue; + + while (true) { + for (const auto &I : Record->bases()) { + const RecordType *Ty = I.getType()->getAs(); + if (!Ty) + continue; + + CXXRecordDecl *RecBase = + cast_or_null(Ty->getDecl()->getDefinition()); + if (!RecBase || (RecBase->isDependentContext() && + !RecBase->isCurrentInstantiation(Record))) + continue; + + Queue.push_back(RecBase); + if (RecBase->getCanonicalDecl() == Base) + return true; + } + + if (Queue.empty()) + break; + Record = Queue.pop_back_val(); // not actually a queue. + } + + return false; +} + bool Sema::CppLookupName(LookupResult &R, Scope *S) { assert(getLangOpts().CPlusPlus && "Can perform only C++ lookup"); @@ -1214,6 +1256,53 @@ // identifier chain. if (LookupQualifiedName(R, Ctx, /*InUnqualifiedLookup=*/true)) return true; + if (!R.wasNotFoundInCurrentInstantiation() && + getLangOpts().MSVCCompat && MSVCInstantiation) { + if (DeclContext *InstCtx = GetMSVCInstantiationContext(*this, Ctx)) { + if (LookupQualifiedName(R, InstCtx, + /*InUnqualifiedLookup=*/true)) { + auto *ND = cast((*R.begin())->getCanonicalDecl()); + if (auto *RD = dyn_cast(ND)) { + if (const auto *Ty = RD->getTypeForDecl()->castAs()) + if (Decl *D = Ty->getDecl()->getCanonicalDecl()) + ND = cast(D); + } + if (ND->isCXXClassMember()) { + auto *Parent = cast(ND->getDeclContext()) + ->getCanonicalDecl(); + auto *DepParent = cast(Ctx); + bool EnableDiag = + isTemplateInstantiation( + Parent->getTemplateSpecializationKind()) || + !isBaseClass(DepParent, Parent); + if (auto *RD = dyn_cast(ND)) { + auto *InstParent = cast(InstCtx); + EnableDiag = + (isTemplateInstantiation( + RD->getTemplateSpecializationKind()) && + InstParent->isProvablyNotDerivedFrom(RD)) || + (!isTemplateInstantiation( + RD->getTemplateSpecializationKind()) && + !isBaseClass(DepParent, RD) && + !(Parent->Encloses(InstCtx) || Parent == InstCtx)); + } + if (EnableDiag) { + auto DB = Diag(R.getNameLoc(), + diag::ext_found_via_dependent_bases_lookup) + << R.getLookupName(); + if (ND->isCXXInstanceMember() && !isa(ND)) + DB << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); + } + if (!isa(ND)) { + R.clear(); + R.setNotFoundInCurrentInstantiation(); + R.setNamingClass(cast(Ctx)); + } + } + return true; + } + } + } } } } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -247,6 +247,21 @@ return true; } +namespace { +/// Do not perform lookup in instantiations during qualified lookup. +class MSVCDoNotLookupInInstance { + Sema &S; + FunctionDecl *MSVCInstantiation = nullptr; + +public: + MSVCDoNotLookupInInstance(Sema &S) + : S(S), MSVCInstantiation(S.MSVCInstantiation) { + S.MSVCInstantiation = nullptr; + } + ~MSVCDoNotLookupInInstance() { S.MSVCInstantiation = MSVCInstantiation; } +}; +} // namespace + void Sema::LookupTemplateName(LookupResult &Found, Scope *S, CXXScopeSpec &SS, QualType ObjectType, @@ -300,7 +315,10 @@ // expression. If the identifier is not found, it is then looked up in // the context of the entire postfix-expression and shall name a class // or function template. - if (S) LookupName(Found, S); + if (S) { + MSVCDoNotLookupInInstance QualifiedLookupScope(*this); + LookupName(Found, S); + } ObjectTypeSearchedInScope = true; AllowFunctionTemplatesInLookup = false; } Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -2008,6 +2008,12 @@ if (Member->getDeclContext() != Pattern) continue; + if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat && + Member->isImplicit()) + if (auto *FD = dyn_cast(Member)) + if (FD->isLateTemplateParsed()) + continue; + if (Member->isInvalidDecl()) { Instantiation->setInvalidDecl(); continue; Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3492,6 +3492,140 @@ return false; } +namespace { +class MSVCTemplateFunctionRebuilderRAII final { + Sema &S; + FunctionDecl *NewTemplateDecl = nullptr; + FunctionDecl *OldMSVCInstantiation = nullptr; + FunctionDecl *PatternDecl = nullptr; + DeclarationNameInfo NameInfo; + +public: + MSVCTemplateFunctionRebuilderRAII(Sema &S, FunctionDecl *PatternDecl, + FunctionDecl *InstDecl) + : S(S), OldMSVCInstantiation(S.MSVCInstantiation), + PatternDecl(PatternDecl) { + if (!S.getLangOpts().DelayedTemplateParsing || + !S.getLangOpts().MSVCCompat || InstDecl->isDependentContext() || + !PatternDecl) + return; + NameInfo = {PatternDecl->getDeclName(), PatternDecl->getLocation()}; + ASTContext &C = S.getASTContext(); + OldMSVCInstantiation = S.MSVCInstantiation; + S.MSVCInstantiation = InstDecl; + + if (auto *CD = dyn_cast(PatternDecl)) { + NewTemplateDecl = CXXConstructorDecl::Create( + C, cast(PatternDecl->getParent()), CD->getLocStart(), + NameInfo, CD->getType(), CD->getTypeSourceInfo(), + CD->isExplicitSpecified(), CD->isInlineSpecified(), CD->isImplicit(), + CD->isConstexpr()); + } else if (auto *DD = dyn_cast(PatternDecl)) { + NewTemplateDecl = CXXDestructorDecl::Create( + C, cast(PatternDecl->getParent()), DD->getLocStart(), + NameInfo, DD->getType(), DD->getTypeSourceInfo(), + DD->isInlineSpecified(), DD->isImplicit()); + } else if (auto *CD = dyn_cast(PatternDecl)) { + NewTemplateDecl = CXXConversionDecl::Create( + C, cast(PatternDecl->getParent()), CD->getLocStart(), + NameInfo, CD->getType(), CD->getTypeSourceInfo(), + CD->isInlineSpecified(), CD->isExplicitSpecified(), CD->isConstexpr(), + CD->getLocEnd()); + } else if (auto *MD = dyn_cast(PatternDecl)) { + NewTemplateDecl = CXXMethodDecl::Create( + C, cast(PatternDecl->getParent()), MD->getLocStart(), + NameInfo, MD->getType(), MD->getTypeSourceInfo(), + MD->getStorageClass(), MD->isInlineSpecified(), MD->isConstexpr(), + MD->getLocEnd()); + } else { + assert(PatternDecl->getKind() == Decl::Function); + NewTemplateDecl = FunctionDecl::Create( + C, PatternDecl->getParent(), PatternDecl->getLocStart(), NameInfo, + PatternDecl->getType(), PatternDecl->getTypeSourceInfo(), + PatternDecl->getStorageClass(), PatternDecl->isInlineSpecified(), + PatternDecl->hasWrittenPrototype(), PatternDecl->isConstexpr()); + } + NewTemplateDecl->setAccess(PatternDecl->getAccess()); + if (PatternDecl->isInlined() && !PatternDecl->isInlineSpecified()) + NewTemplateDecl->setImplicitlyInline(); + switch (PatternDecl->getTemplatedKind()) { + case FunctionDecl::TK_FunctionTemplate: + NewTemplateDecl->setDescribedFunctionTemplate( + PatternDecl->getDescribedFunctionTemplate()); + break; + case FunctionDecl::TK_MemberSpecialization: + NewTemplateDecl->setInstantiationOfMemberFunction( + PatternDecl->getInstantiatedFromMemberFunction(), + PatternDecl->getTemplateSpecializationKind()); + break; + case FunctionDecl::TK_FunctionTemplateSpecialization: { + const ASTTemplateArgumentListInfo *Info = + PatternDecl->getTemplateSpecializationArgsAsWritten(); + TemplateArgumentListInfo Args(Info->LAngleLoc, Info->RAngleLoc); + for (unsigned I = 0, E = Info->NumTemplateArgs; I != E; ++I) + Args.addArgument((*Info)[I]); + NewTemplateDecl->setFunctionTemplateSpecialization( + PatternDecl->getPrimaryTemplate(), + PatternDecl->getTemplateSpecializationArgs(), nullptr, + PatternDecl->getTemplateSpecializationKind(), &Args, + PatternDecl->getPointOfInstantiation()); + break; + } + case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { + UnresolvedSet<4> Decls; + DependentFunctionTemplateSpecializationInfo *Info = + PatternDecl->getDependentSpecializationInfo(); + for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) + Decls.addDecl(Info->getTemplate(I)); + TemplateArgumentListInfo Args(Info->getLAngleLoc(), Info->getRAngleLoc()); + for (unsigned I = 0, E = Info->getNumTemplateArgs(); I != E; ++I) + Args.addArgument(Info->getTemplateArg(I)); + NewTemplateDecl->setDependentTemplateSpecialization(C, Decls, Args); + break; + } + case FunctionDecl::TK_NonTemplate: + break; + } + NewTemplateDecl->setLexicalDeclContext(PatternDecl->getLexicalParent()); + NewTemplateDecl->setInnerLocStart(PatternDecl->getInnerLocStart()); + SmallVector Params; + for (auto *Parm : PatternDecl->parameters()) { + auto *NewParm = ParmVarDecl::Create( + C, NewTemplateDecl, Parm->getLocStart(), Parm->getLocation(), + Parm->getIdentifier(), Parm->getType(), Parm->getTypeSourceInfo(), + Parm->getStorageClass(), Parm->getDefaultArg()); + Params.push_back(NewParm); + } + if (PatternDecl->getNumTemplateParameterLists() > 0) { + SmallVector ParameterLists; + for (unsigned I = 0, E = PatternDecl->getNumTemplateParameterLists(); + I < E; ++I) + ParameterLists.push_back(PatternDecl->getTemplateParameterList(I)); + NewTemplateDecl->setTemplateParameterListsInfo(C, ParameterLists); + } + NewTemplateDecl->setParams(Params); + NewTemplateDecl->setLateTemplateParsed(/*ILT=*/true); + NewTemplateDecl->setImplicit(/*I=*/true); + NewTemplateDecl->setLexicalDeclContext(PatternDecl->getLexicalParent()); + if (PatternDecl->hasAttrs()) { + for (auto *Attr : PatternDecl->attrs()) + NewTemplateDecl->addAttr(Attr); + } + } + FunctionDecl *getTemplateDecl() const { return NewTemplateDecl; } + ~MSVCTemplateFunctionRebuilderRAII() { + if (NewTemplateDecl) { + assert(S.getLangOpts().DelayedTemplateParsing && + S.getLangOpts().MSVCCompat); + NewTemplateDecl->setLateTemplateParsed(/*ILT=*/true); + S.MSVCInstantiation = OldMSVCInstantiation; + if (NewTemplateDecl->isInvalidDecl()) + PatternDecl->setInvalidDecl(/*Invalid=*/true); + } + } +}; +} // namespace + /// \brief Instantiate the definition of the given function from its /// template. /// @@ -3553,8 +3687,16 @@ SavePendingInstantiationsAndVTableUsesRAII SavePendingInstantiationsAndVTableUses(*this, /*Enabled=*/Recursive); + // Do not perform instantiation in MSVC compatibility mode if function is not + // used yet. MSVC instantiates function only if it is used. + if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat && + (Function->isDependentContext() || + (PatternDecl->isLateTemplateParsed() && !DefinitionRequired && + !PatternDecl->isUsed(/*CheckUsedAttr=*/true) && !Function->isUsed()))) + return; // Call the LateTemplateParser callback if there is a need to late parse // a templated function definition. + LateParsedTemplate NewLPT; if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser) { // FIXME: Optimize to allow individual templates to be deserialized. @@ -3563,7 +3705,17 @@ LateParsedTemplate *LPT = LateParsedTemplateMap.lookup(PatternDecl); assert(LPT && "missing LateParsedTemplate"); - LateTemplateParser(OpaqueParser, *LPT); + NewLPT = *LPT; + } + MSVCTemplateFunctionRebuilderRAII MSVCRebuilder( + *this, NewLPT.D ? NewLPT.D->getAsFunction() : nullptr, Function); + if (!Pattern && PatternDecl->isLateTemplateParsed() && LateTemplateParser && + NewLPT.D) { + if (getLangOpts().DelayedTemplateParsing && getLangOpts().MSVCCompat) { + PatternDecl = MSVCRebuilder.getTemplateDecl(); + NewLPT.D = MSVCRebuilder.getTemplateDecl(); + } + LateTemplateParser(OpaqueParser, NewLPT); Pattern = PatternDecl->getBody(PatternDecl); } Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -1400,8 +1400,9 @@ Tok.startToken(); Tok.setLocation(ReadSourceLocation(F, Record, Idx)); Tok.setLength(Record[Idx++]); - if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) - Tok.setIdentifierInfo(II); + if (Tok.getLength()) + if (IdentifierInfo *II = getLocalIdentifier(F, Record[Idx++])) + Tok.setIdentifierInfo(II); Tok.setKind((tok::TokenKind)Record[Idx++]); Tok.setFlag((Token::TokenFlags)Record[Idx++]); return Tok; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -3995,11 +3995,16 @@ void ASTWriter::AddToken(const Token &Tok, RecordDataImpl &Record) { AddSourceLocation(Tok.getLocation(), Record); - Record.push_back(Tok.getLength()); + if (Tok.isAnnotation()) { + assert(!Tok.getAnnotationValue()); + Record.push_back(0); + } else { + Record.push_back(Tok.getLength()); - // FIXME: When reading literal tokens, reconstruct the literal pointer - // if it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); + // FIXME: When reading literal tokens, reconstruct the literal pointer + // if it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + } // FIXME: Should translate token kind to a stable encoding. Record.push_back(Tok.getKind()); // FIXME: Should translate token flags to a stable encoding. Index: test/SemaCXX/ms-property.cpp =================================================================== --- test/SemaCXX/ms-property.cpp +++ test/SemaCXX/ms-property.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility %s -o - | FileCheck %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -emit-pch -o %t %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -include-pch %t -verify %s -ast-print -o - | FileCheck %s +// RUN: %clang_cc1 -ast-print -verify -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing -emit-pch -o %t %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fms-compatibility -fdelayed-template-parsing -include-pch %t -verify %s -ast-print -o - | FileCheck %s // expected-no-diagnostics #ifndef HEADER @@ -42,7 +42,9 @@ St *p2 = 0; // CHECK: St a; St a; - // CHECK-NEXT: int j = (p1->x)[223][11]; + St b; + p2 = &b; + // CHECK: int j = (p1->x)[223][11]; int j = (p1->x)[223][11]; // CHECK-NEXT: (p1->x[23])[1] = j; (p1->x[23])[1] = j; Index: test/SemaTemplate/lookup-dependent-bases.cpp =================================================================== --- test/SemaTemplate/lookup-dependent-bases.cpp +++ test/SemaTemplate/lookup-dependent-bases.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s +// RUN: %clang_cc1 -fms-compatibility -fdelayed-template-parsing -fsyntax-only -verify %s namespace basic { struct C { @@ -12,7 +12,7 @@ template struct B : A { void foo() { - D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} + D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; @@ -20,7 +20,6 @@ } namespace nested_nodep_base { -// There are limits to our hacks, MSVC accepts this, but we don't. struct A { struct D { static void foo2(); }; }; @@ -28,7 +27,7 @@ struct B : T { struct C { void foo() { - D::foo2(); // expected-error {{use of undeclared identifier 'D'}} + D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; }; @@ -46,7 +45,7 @@ struct B { struct C : T { void foo() { - D::foo2(); // expected-warning {{use of undeclared identifier 'D'; unqualified lookup into dependent bases of class template 'C' is a Microsoft extension}} + D::foo2(); // expected-warning {{use of identifier 'D' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; }; Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp =================================================================== --- test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -1,11 +1,11 @@ -// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fno-spell-checking -fsyntax-only -verify %s +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -std=c++1y -fms-compatibility -fdelayed-template-parsing -fno-spell-checking -fsyntax-only -verify %s template class A { public: - void f(T a) { }// expected-note 2{{must qualify identifier to find this declaration in dependent base class}} - void g();// expected-note 2{{must qualify identifier to find this declaration in dependent base class}} + void f(T a) { } + void g(); }; template @@ -16,10 +16,11 @@ f(a); // expected-warning 2{{use of identifier 'f' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} g(); // expected-warning 2{{use of identifier 'g' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } + B() : A() {} }; -template class B; // expected-note {{requested here}} -template class B; // expected-note {{requested here}} +template class B; +template class B; void test() { @@ -64,7 +65,7 @@ class B : public A { public: void f() { - var = 3; // expected-warning {{use of undeclared identifier 'var'; unqualified lookup into dependent bases of class template 'B' is a Microsoft extension}} + var = 3; // expected-warning {{use of identifier 'var' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; @@ -79,8 +80,8 @@ template class A { public: - static void static_func();// expected-note {{must qualify identifier to find this declaration in dependent base class}} - void func();// expected-note {{must qualify identifier to find this declaration in dependent base class}} + static void static_func(); + void func(); }; @@ -129,7 +130,7 @@ template class B { public: - static void g(); // expected-note {{must qualify identifier to find this declaration in dependent base class}} + static void g(); }; template @@ -143,7 +144,7 @@ int main2() { A a; - foo(a); // expected-note {{requested here}} + foo(a); } } @@ -154,13 +155,21 @@ class C { public: int m_hWnd; + static int c_hWnd; +}; + +class B { +public: + static bool b_hWnd; }; template class A : public T { public: void f(int hWnd) { - m_hWnd = 1; // expected-warning {{use of undeclared identifier 'm_hWnd'; unqualified lookup into dependent bases of class template 'A' is a Microsoft extension}} + m_hWnd = 1; // expected-warning {{use of identifier 'm_hWnd' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} + B::b_hWnd = this->m_hWnd < 0; + C::c_hWnd = 0; } }; @@ -176,7 +185,7 @@ template class Base { public: - bool base_fun(void* p) { return false; } // expected-note {{must qualify identifier to find this declaration in dependent base class}} + bool base_fun(void* p) { return false; } operator T*() const { return 0; } }; @@ -185,14 +194,14 @@ public: template bool operator=(const Container& rhs) { - return base_fun(rhs); // expected-warning {{use of identifier 'base_fun' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} + return base_fun(rhs); // expected-warning 2 {{use of identifier 'base_fun' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; void f() { Container text_provider; Container text_provider2; - text_provider2 = text_provider; // expected-note {{in instantiation of function template specialization}} + text_provider2 = text_provider; } } // namespace PR12701 @@ -205,7 +214,7 @@ }; template struct B : T { int foo() { return a; } // expected-warning {{lookup into dependent bases}} - int *bar() { return &a; } // expected-warning {{lookup into dependent bases}} + int *bar() { return &a; } // expected-warning {{lookup into dependent bases}} expected-error {{cannot initialize return object of type 'int *' with an rvalue of type 'int PR16014::A::*'}} int baz() { return T::a; } int T::*qux() { return &T::a; } static int T::*stuff() { return &T::a; } @@ -216,23 +225,21 @@ }; template struct C : T { - int foo() { return b; } // expected-error {{no member named 'b' in 'PR16014::C'}} expected-warning {{lookup into dependent bases}} - int *bar() { return &b; } // expected-error {{no member named 'b' in 'PR16014::C'}} expected-warning {{lookup into dependent bases}} + int foo() { return b; } // expected-error {{use of undeclared identifier 'b'}} + int *bar() { return &b; } // expected-error {{use of undeclared identifier 'b'}} int baz() { return T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} int T::*qux() { return &T::b; } // expected-error {{no member named 'b' in 'PR16014::A'}} int T::*fuz() { return &U::a; } // expected-error {{use of undeclared identifier 'U'}} \ // expected-warning {{unqualified lookup into dependent bases of class template 'C'}} }; -template struct B; +template struct B; // expected-note {{in instantiation of member function 'PR16014::B::bar' requested here}} template struct C; // expected-note-re 1+ {{in instantiation of member function 'PR16014::C::{{.*}}' requested here}} template struct D : T { struct Inner { int foo() { - // FIXME: MSVC can find this in D's base T! Even worse, if ::sa exists, - // clang will use it instead. - return sa; // expected-error {{use of undeclared identifier 'sa'}} + return sa; // expected-warning {{use of identifier 'sa' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} } }; }; @@ -244,14 +251,13 @@ template struct A : T { void foo() { - ::undef(); // expected-error {{no member named 'undef' in the global namespace}} + ::undef(); // expected-error 2 {{no member named 'undef' in the global namespace}} } void bar() { - ::UndefClass::undef(); // expected-error {{no member named 'UndefClass' in the global namespace}} + ::UndefClass::undef(); // expected-error 2 {{no member named 'UndefClass' in the global namespace}} } void baz() { - B::qux(); // expected-error {{use of undeclared identifier 'B'}} \ - // expected-warning {{unqualified lookup into dependent bases of class template 'A'}} + B::qux(); // expected-error {{'PR19233::B::qux' is not a member of class 'PR19233::A'}} } }; @@ -470,7 +476,7 @@ void localClassMethod() { struct X { void bar() { - NameFromBase m; // expected-warning {{lookup into dependent bases}} + NameFromBase m; } } x; x.bar(); @@ -523,8 +529,8 @@ namespace function_template_undef_impl { template void f() { - Undef::staticMethod(); // expected-error {{use of undeclared identifier 'Undef'}} - UndefVar.method(); // expected-error {{use of undeclared identifier 'UndefVar'}} + Undef::staticMethod(); + UndefVar.method(); } } @@ -551,7 +557,7 @@ namespace PR23810 { void f(int); struct Base { - void f(); // expected-note{{must qualify identifier to find this declaration in dependent base class}} + void f(); }; template struct Template : T { void member() { @@ -560,7 +566,7 @@ }; void test() { Template x; - x.member(); // expected-note{{requested here}} + x.member(); }; } @@ -580,19 +586,19 @@ template struct UseUnqualifiedTypeNames : T { void foo() { - void *P = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}} - size_t x = __builtin_offsetof(TheType, f2); // expected-warning {{unqualified lookup}} expected-error {{no type}} + void *P = new TheType; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} + size_t x = __builtin_offsetof(TheType, f2); // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} try { - } catch (TheType) { // expected-warning {{unqualified lookup}} expected-error {{no type}} + } catch (TheType) { // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} } - enum E : IntegerType { E0 = 42 }; // expected-warning {{unqualified lookup}} expected-error {{no type}} - _Atomic(TheType) a; // expected-warning {{unqualified lookup}} expected-error {{no type}} + enum E : IntegerType { E0 = 42 }; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} + _Atomic(TheType) a; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} } void out_of_line(); }; template void UseUnqualifiedTypeNames::out_of_line() { - void *p = new TheType; // expected-warning {{unqualified lookup}} expected-error {{no type}} + void *p = new TheType; // expected-warning 2 {{unqualified lookup}} expected-error {{no type}} } struct Base { typedef int IntegerType; Index: test/SemaTemplate/typename-specifier.cpp =================================================================== --- test/SemaTemplate/typename-specifier.cpp +++ test/SemaTemplate/typename-specifier.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -DMSVC +// RUN: %clang_cc1 -fsyntax-only -verify %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -fms-compatibility -DMSVC +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -fms-compatibility -DMSVC +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-unused -fms-compatibility -fdelayed-template-parsing -DMSVC namespace N { struct A { typedef int type; @@ -139,7 +139,12 @@ namespace missing_typename { -template struct pair {}; // expected-note 7 {{template parameter is declared here}} +#ifdef MSVC +// expected-note@+4 3 {{template parameter is declared here}} +#else +// expected-note@+2 7 {{template parameter is declared here}} +#endif // MSVC +template struct pair {}; template struct map { @@ -157,14 +162,18 @@ }; void foo() { -#ifdef MSVC - // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} -#else +#ifndef MSVC // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} #endif pair i; - pairExampleItemSet::iterator, int> i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}} - pair i; // expected-error-re {{template argument for template type parameter must be a type{{$}}}} +#ifndef MSVC + // expected-error-re@+2 {{template argument for template type parameter must be a type{{$}}}}} +#endif + pairExampleItemSet::iterator, int> i; +#ifndef MSVC + // expected-error-re@+2 {{template argument for template type parameter must be a type{{$}}}}} +#endif + pair i; } #ifdef MSVC // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} @@ -177,9 +186,7 @@ typedef map ExampleItemMap; static void bar() { -#ifdef MSVC - // expected-warning@+4 {{omitted 'typename' is a Microsoft extension}} -#else +#ifndef MSVC // expected-error@+2 {{template argument for template type parameter must be a type; did you forget 'typename'?}} #endif pair i;