Please find attached a couple of patches that are meant to fix the
problems shown by the following examples.

==============
$ cat bug1.cc
template <typename T>
struct Outer {
  template <typename U>
  struct Inner {
    Inner& foo();
  };
};


template <typename T>
template <typename U>
typename Outer<T> ::template Inner<U>&
Outer<T>::Inner<U>::foo() {}
==============

If this is pretty printed using clang, we obtain the following:

==============
$ llvm/Debug+Asserts/bin/clang -cc1 -ast-print bug1.cc
struct __va_list_tag {
    unsigned int gp_offset;
    unsigned int fp_offset;
    void *overflow_arg_area;
    void *reg_save_area;
};
typedef struct __va_list_tag __va_list_tag;
template <typename T> struct Outer {
    template <typename U> struct Inner {
        Inner<U> &foo();
    };
};
typename Outer<T>::Outer<T>::Inner<U> &foo() {
}
==============

The printed return type in the out-of-line definition of method foo has
two problems: the name qualification Outer<T>:: is repeated and the name
qualification Inner<U> is missing the "template" keyword.

The first problem is due to the fact that the NNS is encoded *both* in
the ElaboratedType and in the underlying (dependent)
TemplateSpecializationType: this should be corrected in redundant-nns.patch

The second problem is caused by method Sema::isTemplateName(), which
sometimes builds a QualifiedTemplateName disregarding whether or not the
"template" keyword was specified: this should be corrected in
template-keyword.patch

After applying both patches we obtain:
===============
$ llvm/Debug+Asserts/bin/clang -cc1 -ast-print bug1.cc
[...]
typename Outer<T>::template Inner<U> &foo() {
}
===============

Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h	(revision 109367)
+++ lib/Sema/TreeTransform.h	(working copy)
@@ -558,7 +558,8 @@
       getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args);
     if (T.isNull()) return QualType();
 
-    return SemaRef.Context.getElaboratedType(Keyword, NNS, T);
+    // NOTE: NNS is already recorded in template specialization type T.
+    return SemaRef.Context.getElaboratedType(Keyword, /*NNS=*/0, T);
   }
 
   /// \brief Build a new typename type that refers to an identifier.
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp	(revision 109367)
+++ lib/Sema/SemaTemplate.cpp	(working copy)
@@ -5258,8 +5260,6 @@
   
   TypeSourceInfo *InnerTSI = 0;
   QualType T = GetTypeFromParser(Ty, &InnerTSI);
-  NestedNameSpecifier *NNS
-    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
 
   assert(isa<TemplateSpecializationType>(T) && 
          "Expected a template specialization type");
@@ -5276,7 +5276,7 @@
     else
       Builder.push<TemplateSpecializationTypeLoc>(T).initialize(TemplateLoc);
 
-    T = Context.getElaboratedType(ETK_Typename, NNS, T);
+    T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T);
     ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T);
     TL.setKeywordLoc(TypenameLoc);
     TL.setQualifierRange(SS.getRange());
@@ -5291,7 +5291,10 @@
   DependentTemplateName *DTN =
     TST->getTemplateName().getAsDependentTemplateName();
   assert(DTN && "dependent template has non-dependent name?");
-  T = Context.getDependentTemplateSpecializationType(ETK_Typename, NNS,
+  assert(DTN->getQualifier()
+         == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
+  T = Context.getDependentTemplateSpecializationType(ETK_Typename,
+                                                     DTN->getQualifier(),
                                                      DTN->getIdentifier(),
                                                      TST->getNumArgs(),
                                                      TST->getArgs());
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h	(revision 109428)
+++ include/clang/Parse/Action.h	(working copy)
@@ -281,6 +281,8 @@
   /// \param SS the C++ nested-name-specifier that precedes the template name,
   /// if any.
   ///
+  /// \param hasTemplateKeyword true if the template keyword was specified.
+  ///
   /// \param Name the name that we are querying to determine whether it is
   /// a template.
   ///
@@ -303,6 +305,7 @@
   /// \returns the kind of template that this name refers to.
   virtual TemplateNameKind isTemplateName(Scope *S,
                                           CXXScopeSpec &SS,
+                                          bool hasTemplateKeyword,
                                           UnqualifiedId &Name,
                                           TypeTy *ObjectType,
                                           bool EnteringContext,
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 109428)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -282,7 +282,8 @@
     CXXScopeSpec EmptySS;
     TemplateTy TemplateResult;
     bool MemberOfUnknownSpecialization;
-    if (isTemplateName(S, SS ? *SS : EmptySS, Name, 0, true, TemplateResult,
+    if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false,
+                       Name, 0, true, TemplateResult,
                        MemberOfUnknownSpecialization) == TNK_Type_template) {
       TemplateName TplName = TemplateResult.getAsVal<TemplateName>();
       Diag(IILoc, diag::err_template_missing_args) << TplName;
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp	(revision 109428)
+++ lib/Sema/SemaTemplate.cpp	(working copy)
@@ -97,6 +97,7 @@
 
 TemplateNameKind Sema::isTemplateName(Scope *S,
                                       CXXScopeSpec &SS,
+                                      bool hasTemplateKeyword,
                                       UnqualifiedId &Name,
                                       TypeTy *ObjectTypePtr,
                                       bool EnteringContext,
@@ -150,7 +151,8 @@
     if (SS.isSet() && !SS.isInvalid()) {
       NestedNameSpecifier *Qualifier
         = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
-      Template = Context.getQualifiedTemplateName(Qualifier, false, TD);
+      Template = Context.getQualifiedTemplateName(Qualifier,
+                                                  hasTemplateKeyword, TD);
     } else {
       Template = TemplateName(TD);
     }
@@ -1683,8 +1685,8 @@
     // "template" keyword is now permitted). We follow the C++0x
     // rules, even in C++03 mode with a warning, retroactively applying the DR.
     bool MemberOfUnknownSpecialization;
-    TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
-                                          EnteringContext, Result,
+    TemplateNameKind TNK = isTemplateName(0, SS, TemplateKWLoc.isValid(), Name,
+                                          ObjectType, EnteringContext, Result,
                                           MemberOfUnknownSpecialization);
     if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
         isa<CXXRecordDecl>(LookupCtx) &&
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h	(revision 109428)
+++ lib/Sema/Sema.h	(working copy)
@@ -2900,6 +2900,7 @@
 
   virtual TemplateNameKind isTemplateName(Scope *S,
                                           CXXScopeSpec &SS,
+                                          bool hasTemplateKeyword,
                                           UnqualifiedId &Name,
                                           TypeTy *ObjectType,
                                           bool EnteringContext,
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp	(revision 109428)
+++ lib/Parse/ParseTemplate.cpp	(working copy)
@@ -928,7 +928,9 @@
     
     if (isEndOfTemplateArgument(Tok)) {
       bool MemberOfUnknownSpecialization;
-      TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, Name, 
+      TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS,
+                                               /*hasTemplateKeyword=*/false,
+                                                    Name,
                                                     /*ObjectType=*/0, 
                                                     /*EnteringContext=*/false, 
                                                     Template,
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp	(revision 109428)
+++ lib/Parse/ParseExprCXX.cpp	(working copy)
@@ -294,6 +294,7 @@
       TemplateName.setIdentifier(&II, Tok.getLocation());
       bool MemberOfUnknownSpecialization;
       if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, 
+                                              /*hasTemplateKeyword=*/false,
                                                         TemplateName,
                                                         ObjectType,
                                                         EnteringContext,
@@ -1023,8 +1024,9 @@
         return true;
     } else {
       bool MemberOfUnknownSpecialization;
-      TNK = Actions.isTemplateName(getCurScope(), SS, Id, ObjectType, 
-                                   EnteringContext, Template,
+      TNK = Actions.isTemplateName(getCurScope(), SS,
+                                   TemplateKWLoc.isValid(), Id,
+                                   ObjectType, EnteringContext, Template,
                                    MemberOfUnknownSpecialization);
       
       if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
@@ -1059,7 +1061,8 @@
     UnqualifiedId TemplateName;
     bool MemberOfUnknownSpecialization;
     TemplateName.setIdentifier(Name, NameLoc);
-    TNK = Actions.isTemplateName(getCurScope(), SS, TemplateName, ObjectType, 
+    TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
+                                 TemplateName, ObjectType, 
                                  EnteringContext, Template,
                                  MemberOfUnknownSpecialization);
     break;
@@ -1076,7 +1079,8 @@
       if (TNK == TNK_Non_template)
         return true;
     } else {
-      TNK = Actions.isTemplateName(getCurScope(), SS, TemplateName, ObjectType, 
+      TNK = Actions.isTemplateName(getCurScope(), SS, TemplateKWLoc.isValid(),
+                                   TemplateName, ObjectType, 
                                    EnteringContext, Template,
                                    MemberOfUnknownSpecialization);
       
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp	(revision 109428)
+++ lib/Parse/Parser.cpp	(working copy)
@@ -997,9 +997,10 @@
       TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
       bool MemberOfUnknownSpecialization;
       if (TemplateNameKind TNK
-            = Actions.isTemplateName(getCurScope(), SS, TemplateName, 
-                                     /*ObjectType=*/0, EnteringContext,
-                                     Template, MemberOfUnknownSpecialization)) {
+          = Actions.isTemplateName(getCurScope(), SS,
+                                   /*hasTemplateKeyword=*/false, TemplateName,
+                                   /*ObjectType=*/0, EnteringContext,
+                                   Template, MemberOfUnknownSpecialization)) {
         // Consume the identifier.
         ConsumeToken();
         if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to