On 02/03/2012 09:37 AM, Enea Zaffanella wrote:
On 02/02/2012 11:48 PM, Eli Friedman wrote:
On Fri, Jan 27, 2012 at 1:46 AM, Abramo Bagnara
<[email protected]> wrote:
Author: abramo
Date: Fri Jan 27 03:46:47 2012
New Revision: 149127
URL: http://llvm.org/viewvc/llvm-project?rev=149127&view=rev
Log:
Added source location for the template keyword in AST template-id expressions.
[...]
It looks like this change had semantic side-effects; try the following
testcase (derived from the gcc testsuite):
struct A
{
template<int I>
struct B {
static void b1();
};
};
template<int I> void f2()
{
A::template B<I>::template b1();
}
template void f2<0>();
-Eli
Thanks for spotting this out.
I suspect this is not strictly due to a bug in commit 149127; rather,
the commit has uncovered a latent issue in the code instantiating
DependentScopeDeclRefExpr nodes.
We will try to provide a suitable fix asap.
Enea.
The source of the problem is in method:
bool DependentScopeDeclRefExpr::hasExplicitTemplateArgs() const;
Before the commit, this was strangely returning a positive answer even
for expression
A::template B<I>::template b1();
which has no explicit template arguments at all. As a consequence,
before the commit we were ending up calling
Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo &TemplateArgs);
while after the commit we end up calling
Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
const DeclarationNameInfo &NameInfo);
The attached patch solves the problem by calling function
BuildQualifiedTemplateIdExpr whenever we have an explicit template
argument list *or* a valid template keyword location.
As a side effect, the patch also fixes a pretty-printing problem whereby
in source code such as the following:
template <typename T> void foo() {
T::template foo();
}
clang was printing the call as if there was an explicit template
argument list:
template <typename T> void foo() {
T::template foo<>();
}
After the patch is applied, this is more correctly printed as:
typedef struct __va_list_tag __va_list_tag;
template <typename T> void foo() {
T::template foo();
}
Testcases have been added for both the original and the pretty-printer
issues.
OK to commit?
Enea.
Index: test/SemaTemplate/template-id-printing.cpp
===================================================================
--- test/SemaTemplate/template-id-printing.cpp (revision 149685)
+++ test/SemaTemplate/template-id-printing.cpp (working copy)
@@ -130,3 +130,12 @@
}
} // namespace DSME
+
+namespace DSDRE_withImplicitTemplateArgs {
+
+template <typename T> void foo() {
+ // CHECK: T::template bar();
+ T::template bar();
+}
+
+} // namespace DSDRE_withImplicitTemplateArgs
Index: test/SemaTemplate/template-id-expr.cpp
===================================================================
--- test/SemaTemplate/template-id-expr.cpp (revision 149685)
+++ test/SemaTemplate/template-id-expr.cpp (working copy)
@@ -82,3 +82,17 @@
x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
}
};
+
+struct A {
+ template<int I>
+ struct B {
+ static void b1();
+ };
+};
+
+template<int I>
+void f5() {
+ A::template B<I>::template b1(); // expected-error {{'b1' following the 'template' keyword does not refer to a template}}
+}
+
+template void f5<0>(); // expected-note {{in instantiation of function template specialization 'f5<0>' requested here}}
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h (revision 149685)
+++ include/clang/Sema/Sema.h (working copy)
@@ -2366,7 +2366,6 @@
bool HasTrailingLParen);
ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo);
ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
@@ -3998,12 +3997,12 @@
SourceLocation TemplateKWLoc,
LookupResult &R,
bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs);
ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo &TemplateArgs);
+ const TemplateArgumentListInfo *TemplateArgs);
TemplateNameKind ActOnDependentTemplateName(Scope *S,
CXXScopeSpec &SS,
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h (revision 149685)
+++ include/clang/AST/ExprCXX.h (working copy)
@@ -2022,7 +2022,7 @@
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
- const TemplateArgumentListInfo &Args,
+ const TemplateArgumentListInfo *Args,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End);
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h (revision 149685)
+++ lib/Sema/TreeTransform.h (working copy)
@@ -2032,12 +2032,11 @@
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
- if (TemplateArgs)
+ if (TemplateArgs || TemplateKWLoc.isValid())
return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc,
- NameInfo, *TemplateArgs);
+ NameInfo, TemplateArgs);
- return getSema().BuildQualifiedDeclarationNameExpr(SS, TemplateKWLoc,
- NameInfo);
+ return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo);
}
/// \brief Build a new template-id expression.
@@ -2048,7 +2047,7 @@
SourceLocation TemplateKWLoc,
LookupResult &R,
bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs) {
return getSema().BuildTemplateIdExpr(SS, TemplateKWLoc, R, RequiresADL,
TemplateArgs);
}
@@ -7361,8 +7360,9 @@
SourceLocation TemplateKWLoc = Old->getTemplateKeywordLoc();
- // If we have no template arguments, it's a normal declaration name.
- if (!Old->hasExplicitTemplateArgs())
+ // If we have neither explicit template arguments, nor the template keyword,
+ // it's a normal declaration name.
+ if (!Old->hasExplicitTemplateArgs() && !TemplateKWLoc.isValid())
return getDerived().RebuildDeclarationNameExpr(SS, R, Old->requiresADL());
// If we have template arguments, rebuild them, then rebuild the
@@ -7374,7 +7374,7 @@
return ExprError();
return getDerived().RebuildTemplateIdExpr(SS, TemplateKWLoc, R,
- Old->requiresADL(), TransArgs);
+ Old->requiresADL(), &TransArgs);
}
template<typename Derived>
Index: lib/Sema/SemaOverload.cpp
===================================================================
--- lib/Sema/SemaOverload.cpp (revision 149685)
+++ lib/Sema/SemaOverload.cpp (working copy)
@@ -9294,9 +9294,9 @@
if ((*R.begin())->isCXXClassMember())
NewFn = SemaRef.BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc,
R, ExplicitTemplateArgs);
- else if (ExplicitTemplateArgs)
+ else if (ExplicitTemplateArgs || TemplateKWLoc.isValid())
NewFn = SemaRef.BuildTemplateIdExpr(SS, TemplateKWLoc, R, false,
- *ExplicitTemplateArgs);
+ ExplicitTemplateArgs);
else
NewFn = SemaRef.BuildDeclarationNameExpr(SS, R, false);
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp (revision 149685)
+++ lib/Sema/SemaTemplate.cpp (working copy)
@@ -2200,7 +2200,7 @@
SourceLocation TemplateKWLoc,
LookupResult &R,
bool RequiresADL,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs) {
// FIXME: Can we do any checking at this point? I guess we could check the
// template arguments that we have against the template name, if the template
// name refers to a single template. That's not a terribly common case,
@@ -2234,13 +2234,13 @@
Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
- const TemplateArgumentListInfo &TemplateArgs) {
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(TemplateArgs || TemplateKWLoc.isValid());
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) ||
DC->isDependentContext() ||
RequireCompleteDeclContext(SS, DC))
- return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo,
- &TemplateArgs);
+ return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs);
bool MemberOfUnknownSpecialization;
LookupResult R(*this, NameInfo, LookupOrdinaryName);
Index: lib/Sema/SemaExprMember.cpp
===================================================================
--- lib/Sema/SemaExprMember.cpp (revision 149685)
+++ lib/Sema/SemaExprMember.cpp (working copy)
@@ -232,8 +232,8 @@
case IMA_Mixed_StaticContext:
case IMA_Unresolved_StaticContext:
case IMA_Field_Uneval_Context:
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, *TemplateArgs);
+ if (TemplateArgs || TemplateKWLoc.isValid())
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
return BuildDeclarationNameExpr(SS, R, false);
case IMA_Error_StaticContext:
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp (revision 149685)
+++ lib/Sema/SemaExpr.cpp (working copy)
@@ -1652,8 +1652,8 @@
R, TemplateArgs);
}
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, *TemplateArgs);
+ if (TemplateArgs || TemplateKWLoc.isValid())
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
return BuildDeclarationNameExpr(SS, R, ADL);
}
@@ -1664,11 +1664,11 @@
/// this path.
ExprResult
Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS,
- SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo) {
DeclContext *DC;
if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext())
- return BuildDependentDeclRefExpr(SS, TemplateKWLoc, NameInfo, 0);
+ return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(),
+ NameInfo, /*TemplateArgs=*/0);
if (RequireCompleteDeclContext(SS, DC))
return ExprError();
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp (revision 149685)
+++ lib/AST/ExprCXX.cpp (working copy)
@@ -200,15 +200,17 @@
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
bool ADL,
- const TemplateArgumentListInfo &Args,
- UnresolvedSetIterator Begin,
- UnresolvedSetIterator End)
+ const TemplateArgumentListInfo *Args,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End)
{
+ assert(Args || TemplateKWLoc.isValid());
+ unsigned num_args = Args ? Args->size() : 0;
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
- ASTTemplateKWAndArgsInfo::sizeFor(Args.size()));
+ ASTTemplateKWAndArgsInfo::sizeFor(num_args));
return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
TemplateKWLoc, NameInfo,
- ADL, /*Overload*/ true, &Args,
+ ADL, /*Overload*/ true, Args,
Begin, End, /*StdIsAssociated=*/false);
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits