瀏覽代碼

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.


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

Douglas Gregor 13 年之前
父節點
當前提交
5a7a5bb209
共有 3 個文件被更改,包括 50 次插入11 次删除
  1. 4 2
      include/clang/Sema/Sema.h
  2. 21 9
      lib/Sema/SemaTemplate.cpp
  3. 25 0
      test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp

+ 4 - 2
include/clang/Sema/Sema.h

@@ -4131,8 +4131,10 @@ public:
   //===--------------------------------------------------------------------===//
   // C++ Templates [C++ 14]
   //
-  void FilterAcceptableTemplateNames(LookupResult &R);
-  bool hasAnyAcceptableTemplateNames(LookupResult &R);
+  void FilterAcceptableTemplateNames(LookupResult &R, 
+                                     bool AllowFunctionTemplates = true);
+  bool hasAnyAcceptableTemplateNames(LookupResult &R, 
+                                     bool AllowFunctionTemplates = true);
 
   void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS,
                           QualType ObjectType, bool EnteringContext,

+ 21 - 9
lib/Sema/SemaTemplate.cpp

@@ -44,11 +44,16 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps,
 /// of a template and, if so, return that template declaration. Otherwise,
 /// returns NULL.
 static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
-                                           NamedDecl *Orig) {
+                                           NamedDecl *Orig,
+                                           bool AllowFunctionTemplates) {
   NamedDecl *D = Orig->getUnderlyingDecl();
 
-  if (isa<TemplateDecl>(D))
+  if (isa<TemplateDecl>(D)) {
+    if (!AllowFunctionTemplates && isa<FunctionTemplateDecl>(D))
+      return 0;
+    
     return Orig;
+  }
 
   if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) {
     // C++ [temp.local]p1:
@@ -78,13 +83,15 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context,
   return 0;
 }
 
-void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
+void Sema::FilterAcceptableTemplateNames(LookupResult &R, 
+                                         bool AllowFunctionTemplates) {
   // The set of class templates we've already seen.
   llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates;
   LookupResult::Filter filter = R.makeFilter();
   while (filter.hasNext()) {
     NamedDecl *Orig = filter.next();
-    NamedDecl *Repl = isAcceptableTemplateName(Context, Orig);
+    NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, 
+                                               AllowFunctionTemplates);
     if (!Repl)
       filter.erase();
     else if (Repl != Orig) {
@@ -114,9 +121,10 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) {
   filter.done();
 }
 
-bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) {
+bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R,
+                                         bool AllowFunctionTemplates) {
   for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I)
-    if (isAcceptableTemplateName(Context, *I))
+    if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates))
       return true;
   
   return false;
@@ -268,13 +276,13 @@ void Sema::LookupTemplateName(LookupResult &Found,
   }
 
   bool ObjectTypeSearchedInScope = false;
+  bool AllowFunctionTemplatesInLookup = true;
   if (LookupCtx) {
     // Perform "qualified" name lookup into the declaration context we
     // computed, which is either the type of the base of a member access
     // expression or the declaration context associated with a prior
     // nested-name-specifier.
     LookupQualifiedName(Found, LookupCtx);
-
     if (!ObjectType.isNull() && Found.empty()) {
       // C++ [basic.lookup.classref]p1:
       //   In a class member access expression (5.2.5), if the . or -> token is
@@ -287,6 +295,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
       //   or function template.
       if (S) LookupName(Found, S);
       ObjectTypeSearchedInScope = true;
+      AllowFunctionTemplatesInLookup = false;
     }
   } else if (isDependent && (!S || ObjectType.isNull())) {
     // We cannot look into a dependent object type or nested nme
@@ -296,6 +305,9 @@ void Sema::LookupTemplateName(LookupResult &Found,
   } else {
     // Perform unqualified name lookup in the current scope.
     LookupName(Found, S);
+    
+    if (!ObjectType.isNull())
+      AllowFunctionTemplatesInLookup = false;
   }
 
   if (Found.empty() && !isDependent) {
@@ -335,7 +347,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
     }
   }
 
-  FilterAcceptableTemplateNames(Found);
+  FilterAcceptableTemplateNames(Found, AllowFunctionTemplatesInLookup);
   if (Found.empty()) {
     if (isDependent)
       MemberOfUnknownSpecialization = true;
@@ -351,7 +363,7 @@ void Sema::LookupTemplateName(LookupResult &Found,
     LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(),
                             LookupOrdinaryName);
     LookupName(FoundOuter, S);
-    FilterAcceptableTemplateNames(FoundOuter);
+    FilterAcceptableTemplateNames(FoundOuter, /*AllowFunctionTemplates=*/false);
 
     if (FoundOuter.empty()) {
       //   - if the name is not found, the name found in the class of the

+ 25 - 0
test/CXX/basic/basic.lookup/basic.lookup.classref/p1.cpp

@@ -62,3 +62,28 @@ namespace rdar9915664 {
     }
   };
 }
+
+namespace PR11856 {
+  template<typename T> T end(T);
+
+  template <typename T>
+  void Foo() {
+    T it1;
+    if (it1->end < it1->end) {
+    }
+  }
+
+  template<typename T> T *end(T*);
+
+  class X { };
+  template <typename T>
+  void Foo2() {
+    T it1;
+    if (it1->end < it1->end) {
+    }
+
+    X *x;
+    if (x->end < 7) {  // expected-error{{no member named 'end' in 'PR11856::X'}}
+    }
+  }
+}