Skip to content

Commit 50a3cdd

Browse files
committed
When determining whether an identifier followed by a '<' in a member
access expression is the start of a template-id, ignore function templates found in the context of the entire postfix-expression. Fixes PR11856. llvm-svn: 152520
1 parent 631a486 commit 50a3cdd

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4131,8 +4131,10 @@ class Sema {
41314131
//===--------------------------------------------------------------------===//
41324132
// C++ Templates [C++ 14]
41334133
//
4134-
void FilterAcceptableTemplateNames(LookupResult &R);
4135-
bool hasAnyAcceptableTemplateNames(LookupResult &R);
4134+
void FilterAcceptableTemplateNames(LookupResult &R,
4135+
bool AllowFunctionTemplates = true);
4136+
bool hasAnyAcceptableTemplateNames(LookupResult &R,
4137+
bool AllowFunctionTemplates = true);
41364138

41374139
void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
41384140
QualType ObjectType, bool EnteringContext,

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,16 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
4444
/// of a template and, if so, return that template declaration. Otherwise,
4545
/// returns NULL.
4646
static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
47-
NamedDecl *Orig) {
47+
NamedDecl *Orig,
48+
bool AllowFunctionTemplates) {
4849
NamedDecl *D = Orig->getUnderlyingDecl();
4950

50-
if (isa<TemplateDecl>(D))
51+
if (isa<TemplateDecl>(D)) {
52+
if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))
53+
return 0;
54+
5155
return Orig;
56+
}
5257

5358
if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
5459
// C++ [temp.local]p1:
@@ -78,13 +83,15 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
7883
return 0;
7984
}
8085

81-
void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
86+
void Sema::FilterAcceptableTemplateNames(LookupResult &R,
87+
bool AllowFunctionTemplates) {
8288
// The set of class templates we've already seen.
8389
llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
8490
LookupResult::Filter filter = R.makeFilter();
8591
while (filter.hasNext()) {
8692
NamedDecl *Orig = filter.next();
87-
NamedDecl *Repl = isAcceptableTemplateName(Context, Orig);
93+
NamedDecl *Repl = isAcceptableTemplateName(Context, Orig,
94+
AllowFunctionTemplates);
8895
if (!Repl)
8996
filter.erase();
9097
else if (Repl != Orig) {
@@ -114,9 +121,10 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
114121
filter.done();
115122
}
116123

117-
bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) {
124+
bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
125+
bool AllowFunctionTemplates) {
118126
for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
119-
if (isAcceptableTemplateName(Context, *I))
127+
if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates))
120128
return true;
121129

122130
return false;
@@ -268,13 +276,13 @@ void Sema::LookupTemplateName(LookupResult &Found,
268276
}
269277

270278
bool ObjectTypeSearchedInScope = false;
279+
bool AllowFunctionTemplatesInLookup = true;
271280
if (LookupCtx) {
272281
// Perform "qualified" name lookup into the declaration context we
273282
// computed, which is either the type of the base of a member access
274283
// expression or the declaration context associated with a prior
275284
// nested-name-specifier.
276285
LookupQualifiedName(Found, LookupCtx);
277-
278286
if (!ObjectType.isNull() && Found.empty()) {
279287
// C++ [basic.lookup.classref]p1:
280288
// In a class member access expression (5.2.5), if the . or -> token is
@@ -287,6 +295,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
287295
// or function template.
288296
if (S) LookupName(Found, S);
289297
ObjectTypeSearchedInScope = true;
298+
AllowFunctionTemplatesInLookup = false;
290299
}
291300
} else if (isDependent && (!S || ObjectType.isNull())) {
292301
// We cannot look into a dependent object type or nested nme
@@ -296,6 +305,9 @@ void Sema::LookupTemplateName(LookupResult &Found,
296305
} else {
297306
// Perform unqualified name lookup in the current scope.
298307
LookupName(Found, S);
308+
309+
if (!ObjectType.isNull())
310+
AllowFunctionTemplatesInLookup = false;
299311
}
300312

301313
if (Found.empty() && !isDependent) {
@@ -335,7 +347,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
335347
}
336348
}
337349

338-
FilterAcceptableTemplateNames(Found);
350+
FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
339351
if (Found.empty()) {
340352
if (isDependent)
341353
MemberOfUnknownSpecialization = true;
@@ -351,7 +363,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
351363
LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
352364
LookupOrdinaryName);
353365
LookupName(FoundOuter, S);
354-
FilterAcceptableTemplateNames(FoundOuter);
366+
FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false);
355367

356368
if (FoundOuter.empty()) {
357369
// - if the name is not found, the name found in the class of the

clang/test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,28 @@ namespace rdar9915664 {
6262
}
6363
};
6464
}
65+
66+
namespace PR11856 {
67+
template<typename T> T end(T);
68+
69+
template <typename T>
70+
void Foo() {
71+
T it1;
72+
if (it1->end < it1->end) {
73+
}
74+
}
75+
76+
template<typename T> T *end(T*);
77+
78+
class X { };
79+
template <typename T>
80+
void Foo2() {
81+
T it1;
82+
if (it1->end < it1->end) {
83+
}
84+
85+
X *x;
86+
if (x->end < 7) { // expected-error{{no member named 'end' in 'PR11856::X'}}
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)