[cfe-commits] r116911 - in /cfe/trunk: lib/Sema/SemaTemplate.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp
John McCall
rjmccall at apple.com
Tue Oct 19 22:44:58 PDT 2010
Author: rjmccall
Date: Wed Oct 20 00:44:58 2010
New Revision: 116911
URL: http://llvm.org/viewvc/llvm-project?rev=116911&view=rev
Log:
When matching template parameter lists to template-ids in a scope specifier
on a friend declaration, skip template-ids which do not depend on the
current parameter list.
Modified:
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=116911&r1=116910&r2=116911&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Oct 20 00:44:58 2010
@@ -20,6 +20,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ParsedTemplate.h"
@@ -1217,6 +1218,70 @@
return Invalid;
}
+namespace {
+
+/// A class which looks for a use of a certain level of template
+/// parameter.
+struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
+ typedef RecursiveASTVisitor<DependencyChecker> super;
+
+ unsigned Depth;
+ bool Match;
+
+ DependencyChecker(TemplateParameterList *Params) : Match(false) {
+ NamedDecl *ND = Params->getParam(0);
+ if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) {
+ Depth = PD->getDepth();
+ } else if (NonTypeTemplateParmDecl *PD =
+ dyn_cast<NonTypeTemplateParmDecl>(ND)) {
+ Depth = PD->getDepth();
+ } else {
+ Depth = cast<TemplateTemplateParmDecl>(ND)->getDepth();
+ }
+ }
+
+ bool Matches(unsigned ParmDepth) {
+ if (ParmDepth >= Depth) {
+ Match = true;
+ return true;
+ }
+ return false;
+ }
+
+ bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
+ return !Matches(T->getDepth());
+ }
+
+ bool TraverseTemplateName(TemplateName N) {
+ if (TemplateTemplateParmDecl *PD =
+ dyn_cast_or_null<TemplateTemplateParmDecl>(N.getAsTemplateDecl()))
+ if (Matches(PD->getDepth())) return false;
+ return super::TraverseTemplateName(N);
+ }
+
+ bool VisitDeclRefExpr(DeclRefExpr *E) {
+ if (NonTypeTemplateParmDecl *PD =
+ dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
+ if (PD->getDepth() == Depth) {
+ Match = true;
+ return false;
+ }
+ }
+ return super::VisitDeclRefExpr(E);
+ }
+};
+}
+
+/// Determines whether a template-id depends on the given parameter
+/// list.
+static bool
+DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId,
+ TemplateParameterList *Params) {
+ DependencyChecker Checker(Params);
+ Checker.TraverseType(QualType(TemplateId, 0));
+ return Checker.Match;
+}
+
/// \brief Match the given template parameter lists to the given scope
/// specifier, returning the template parameter list that applies to the
/// name.
@@ -1310,12 +1375,24 @@
// Match the template-ids found in the specifier to the template parameter
// lists.
- unsigned Idx = 0;
+ unsigned ParamIdx = 0, TemplateIdx = 0;
for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size();
- Idx != NumTemplateIds; ++Idx) {
- QualType TemplateId = QualType(TemplateIdsInSpecifier[Idx], 0);
+ TemplateIdx != NumTemplateIds; ++TemplateIdx) {
+ const TemplateSpecializationType *TemplateId
+ = TemplateIdsInSpecifier[TemplateIdx];
bool DependentTemplateId = TemplateId->isDependentType();
- if (Idx >= NumParamLists) {
+
+ // In friend declarations we can have template-ids which don't
+ // depend on the corresponding template parameter lists. But
+ // assume that empty parameter lists are supposed to match this
+ // template-id.
+ if (IsFriend && ParamIdx < NumParamLists && ParamLists[ParamIdx]->size()) {
+ if (!DependentTemplateId ||
+ !DependsOnTemplateParameters(TemplateId, ParamLists[ParamIdx]))
+ continue;
+ }
+
+ if (ParamIdx >= NumParamLists) {
// We have a template-id without a corresponding template parameter
// list.
@@ -1329,7 +1406,7 @@
// FIXME: the location information here isn't great.
Diag(SS.getRange().getBegin(),
diag::err_template_spec_needs_template_parameters)
- << TemplateId
+ << QualType(TemplateId, 0)
<< SS.getRange();
Invalid = true;
} else {
@@ -1358,35 +1435,38 @@
}
if (ExpectedTemplateParams)
- TemplateParameterListsAreEqual(ParamLists[Idx],
+ TemplateParameterListsAreEqual(ParamLists[ParamIdx],
ExpectedTemplateParams,
true, TPL_TemplateMatch);
- CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember);
- } else if (ParamLists[Idx]->size() > 0)
- Diag(ParamLists[Idx]->getTemplateLoc(),
+ CheckTemplateParameterList(ParamLists[ParamIdx], 0,
+ TPC_ClassTemplateMember);
+ } else if (ParamLists[ParamIdx]->size() > 0)
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
diag::err_template_param_list_matches_nontemplate)
<< TemplateId
- << ParamLists[Idx]->getSourceRange();
+ << ParamLists[ParamIdx]->getSourceRange();
else
IsExplicitSpecialization = true;
+
+ ++ParamIdx;
}
// If there were at least as many template-ids as there were template
// parameter lists, then there are no template parameter lists remaining for
// the declaration itself.
- if (Idx >= NumParamLists)
+ if (ParamIdx >= NumParamLists)
return 0;
// If there were too many template parameter lists, complain about that now.
- if (Idx != NumParamLists - 1) {
- while (Idx < NumParamLists - 1) {
- bool isExplicitSpecHeader = ParamLists[Idx]->size() == 0;
- Diag(ParamLists[Idx]->getTemplateLoc(),
+ if (ParamIdx != NumParamLists - 1) {
+ while (ParamIdx < NumParamLists - 1) {
+ bool isExplicitSpecHeader = ParamLists[ParamIdx]->size() == 0;
+ Diag(ParamLists[ParamIdx]->getTemplateLoc(),
isExplicitSpecHeader? diag::warn_template_spec_extra_headers
: diag::err_template_spec_extra_headers)
- << SourceRange(ParamLists[Idx]->getTemplateLoc(),
- ParamLists[Idx]->getRAngleLoc());
+ << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(),
+ ParamLists[ParamIdx]->getRAngleLoc());
if (isExplicitSpecHeader && !ExplicitSpecializationsInSpecifier.empty()) {
Diag(ExplicitSpecializationsInSpecifier.back()->getLocation(),
@@ -1401,7 +1481,7 @@
if (!isExplicitSpecHeader)
Invalid = true;
- ++Idx;
+ ++ParamIdx;
}
}
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=116911&r1=116910&r2=116911&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Wed Oct 20 00:44:58 2010
@@ -307,3 +307,28 @@
template class B<int>; // expected-note {{in instantiation}}
}
+
+namespace test15 {
+ template <class T> class B;
+ template <class T> class A {
+ friend void B<T>::foo();
+
+ // This shouldn't be misrecognized as a templated-scoped reference.
+ template <class U> friend void B<T>::bar(U);
+
+ static void foo(); // expected-note {{declared private here}}
+ };
+
+ template <class T> class B {
+ void foo() { return A<long>::foo(); } // expected-error {{'foo' is a private member of 'test15::A<long>'}}
+ };
+
+ template <> class B<float> {
+ void foo() { return A<float>::foo(); }
+ template <class U> void bar(U u) {
+ (void) A<float>::foo();
+ }
+ };
+
+ template class B<int>; // expected-note {{in instantiation}}
+}
More information about the cfe-commits
mailing list