summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorReid Kleckner <reid@kleckner.net>2014-06-11 00:01:28 +0000
committerReid Kleckner <reid@kleckner.net>2014-06-11 00:01:28 +0000
commitfc142cb60229143db3de1f60bcd561deebe8c2c1 (patch)
treefd789c8c18fe60540c9178cdc8e629746cc2c9c5 /lib/Sema/SemaExpr.cpp
parentae83eca8d28ac331d927c74ce90066e14b6591a5 (diff)
downloadclang-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.cpp74
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.