diff options
author | Reid Kleckner <reid@kleckner.net> | 2014-06-11 00:01:28 +0000 |
---|---|---|
committer | Reid Kleckner <reid@kleckner.net> | 2014-06-11 00:01:28 +0000 |
commit | fc142cb60229143db3de1f60bcd561deebe8c2c1 (patch) | |
tree | fd789c8c18fe60540c9178cdc8e629746cc2c9c5 /lib/Sema/SemaExpr.cpp | |
parent | ae83eca8d28ac331d927c74ce90066e14b6591a5 (diff) | |
download | clang-fc142cb60229143db3de1f60bcd561deebe8c2c1.tar.gz clang-fc142cb60229143db3de1f60bcd561deebe8c2c1.tar.bz2 clang-fc142cb60229143db3de1f60bcd561deebe8c2c1.tar.xz |
Allow lookup into dependent bases in more places under -fms-compatibility
We currently allow unqualified lookup for instance methods but not
static methods because we can't recover with a semantic 'this->'
insertion.
ATL headers have static methods that do unqualified lookup into
dependent base classes. The pattern looks like:
template <typename T> struct Foo : T {
static int *getBarFromT() { return Bar; }
};
Now we recover as if the user had written:
template <typename T> struct Foo : T {
static int *getBarFromT() { return Foo::Bar; }
};
... which will eventually look up Bar in T at instantiation time.
Now we emit a diagnostic in both cases, and delay lookup in other
contexts where 'this' is available and refers to a class with dependent
bases.
Reviewed by: rsmith
Differential Revision: http://reviews.llvm.org/D4079
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@210611 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 74 |
1 files changed, 52 insertions, 22 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 041a9eb9d4..408a8a4089 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1762,7 +1762,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, // TODO: fixit for inserting 'Base<T>::' in the other cases. // Actually quite difficult! if (getLangOpts().MSVCCompat) - diagnostic = diag::warn_found_via_dependent_bases_lookup; + diagnostic = diag::ext_found_via_dependent_bases_lookup; if (isInstance) { Diag(R.getNameLoc(), diagnostic) << Name << FixItHint::CreateInsertion(R.getNameLoc(), "this->"); @@ -1927,6 +1927,54 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } +/// In Microsoft mode, if we are inside a template class whose parent class has +/// dependent base classes, and we can't resolve an unqualified identifier, then +/// assume the identifier is a member of a dependent base class. We can only +/// recover successfully in static methods, instance methods, and other contexts +/// where 'this' is available. This doesn't precisely match MSVC's +/// instantiation model, but it's close enough. +static Expr * +recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, + DeclarationNameInfo &NameInfo, + SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo *TemplateArgs) { + // Only try to recover from lookup into dependent bases in static methods or + // contexts where 'this' is available. + QualType ThisType = S.getCurrentThisType(); + const CXXRecordDecl *RD = nullptr; + if (!ThisType.isNull()) + RD = ThisType->getPointeeType()->getAsCXXRecordDecl(); + else if (auto *MD = dyn_cast<CXXMethodDecl>(S.CurContext)) + RD = MD->getParent(); + if (!RD || !RD->hasAnyDependentBases()) + return nullptr; + + // Diagnose this as unqualified lookup into a dependent base class. If 'this' + // is available, suggest inserting 'this->' as a fixit. + SourceLocation Loc = NameInfo.getLoc(); + DiagnosticBuilder DB = + S.Diag(Loc, diag::ext_undeclared_unqual_id_with_dependent_base) + << NameInfo.getName() << RD; + + if (!ThisType.isNull()) { + DB << FixItHint::CreateInsertion(Loc, "this->"); + return CXXDependentScopeMemberExpr::Create( + Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, + /*Op=*/SourceLocation(), NestedNameSpecifierLoc(), TemplateKWLoc, + /*FirstQualifierInScope=*/nullptr, NameInfo, TemplateArgs); + } + + // Synthesize a fake NNS that points to the derived class. This will + // perform name lookup during template instantiation. + CXXScopeSpec SS; + auto *NNS = + NestedNameSpecifier::Create(Context, nullptr, true, RD->getTypeForDecl()); + SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc)); + return DependentScopeDeclRefExpr::Create( + Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, + TemplateArgs); +} + ExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -2034,28 +2082,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { - // In Microsoft mode, if we are inside a template class member function - // whose parent class has dependent base classes, and we can't resolve - // an unqualified identifier, then assume the identifier is a member of a - // dependent base class. The goal is to postpone name lookup to - // instantiation time to be able to search into the type dependent base - // classes. - // FIXME: If we want 100% compatibility with MSVC, we will have delay all - // unqualified name lookup. Any name lookup during template parsing means - // clang might find something that MSVC doesn't. For now, we only handle - // the common case of members of a dependent base class. if (SS.isEmpty() && getLangOpts().MSVCCompat) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext); - if (MD && MD->isInstance() && MD->getParent()->hasAnyDependentBases()) { - QualType ThisType = MD->getThisType(Context); - // Since the 'this' expression is synthesized, we don't need to - // perform the double-lookup check. - NamedDecl *FirstQualifierInScope = nullptr; - return CXXDependentScopeMemberExpr::Create( - Context, /*This=*/nullptr, ThisType, /*IsArrow=*/true, - /*Op=*/SourceLocation(), SS.getWithLocInContext(Context), - TemplateKWLoc, FirstQualifierInScope, NameInfo, TemplateArgs); - } + if (Expr *E = recoverFromMSUnqualifiedLookup(*this, Context, NameInfo, + TemplateKWLoc, TemplateArgs)) + return E; } // Don't diagnose an empty lookup for inline assmebly. |