[cfe-commits] r71408 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Decl.h include/clang/AST/DeclTemplate.h include/clang/AST/Type.h lib/AST/ASTContext.cpp lib/AST/Decl.cpp lib/AST/DeclTemplate.cpp lib/AST/Type.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/injected-class-name.cpp

Douglas Gregor dgregor at apple.com
Sun May 10 15:57:21 PDT 2009


Author: dgregor
Date: Sun May 10 17:57:19 2009
New Revision: 71408

URL: http://llvm.org/viewvc/llvm-project?rev=71408&view=rev
Log:
Implement the semantics of the injected-class-name within a class
template. The injected-class-name is either a type or a template,
depending on whether a '<' follows it. As a type, the
injected-class-name's template argument list contains its template
parameters in declaration order.

As part of this, add logic for canonicalizing declarations, and be
sure to canonicalize declarations used in template names and template
arguments. 

A TagType is dependent if the declaration it references is dependent.

I'm not happy about the rather complicated protocol needed to use
ASTContext::getTemplateSpecializationType.


Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/injected-class-name.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Sun May 10 17:57:19 2009
@@ -564,6 +564,9 @@
     return T1.getUnqualifiedType() == T2.getUnqualifiedType();
   }
 
+  /// \brief Retrieves the "canonical" declaration of the given declaration.
+  Decl *getCanonicalDecl(Decl *D);
+
   /// \brief Retrieves the "canonical" declaration of the given tag
   /// declaration.
   ///
@@ -571,11 +574,11 @@
   /// either the definition of the tag (if it is a complete type) or
   /// the first declaration of that tag.
   TagDecl *getCanonicalDecl(TagDecl *Tag) {
-    QualType T = getTagDeclType(Tag);
-    return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType)
-                           ->getDecl());
+    return cast<TagDecl>(getCanonicalDecl((Decl *)Tag));
   }
 
+  /// \brief Retrieves the "canonical" declaration of 
+
   /// \brief Retrieves the "canonical" nested name specifier for a
   /// given nested name specifier.
   ///

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sun May 10 17:57:19 2009
@@ -902,7 +902,12 @@
   bool isDefinition() const {
     return IsDefinition;
   }
-  
+
+  /// \brief Whether this declaration declares a type that is
+  /// dependent, i.e., a type that somehow depends on template
+  /// parameters.
+  bool isDependentType() const;
+
   /// @brief Starts the definition of this tag declaration.
   /// 
   /// This method should be invoked at the beginning of the definition

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Sun May 10 17:57:19 2009
@@ -674,6 +674,9 @@
     /// \brief The class template specializations for this class
     /// template, including explicit specializations and instantiations.
     llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
+
+    /// \brief The injected-class-name type for this class template.
+    QualType InjectedClassNameType;
   };
 
   /// \brief Previous declaration of this class template.
@@ -700,6 +703,11 @@
     return static_cast<CXXRecordDecl *>(TemplatedDecl);
   }
 
+  /// \brief Retrieve the previous declaration of this template.
+  ClassTemplateDecl *getPreviousDeclaration() const {
+    return PreviousDeclaration;
+  }
+
   /// Create a class template node.
   static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
                                    SourceLocation L,
@@ -713,6 +721,22 @@
     return CommonPtr->Specializations;
   }
 
+  /// \brief Retrieve the type of the injected-class-name for this
+  /// class template.
+  ///
+  /// The injected-class-name for a class template \c X is \c
+  /// X<template-args>, where \c template-args is formed from the
+  /// template arguments that correspond to the template parameters of
+  /// \c X. For example:
+  ///
+  /// \code
+  /// template<typename T, int N>
+  /// struct array {
+  ///   typedef array this_type; // "array" is equivalent to "array<T, N>"
+  /// };
+  /// \endcode
+  QualType getInjectedClassNameType(ASTContext &Context);
+
   // Implement isa/cast/dyncast support
   static bool classof(const Decl *D)
   { return D->getKind() == ClassTemplate; }

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sun May 10 17:57:19 2009
@@ -1281,11 +1281,7 @@
   friend class TagDecl;
 
 protected:
-  // FIXME: We'll need the user to pass in information about whether
-  // this type is dependent or not, because we don't have enough
-  // information to compute it here.
-  TagType(TypeClass TC, TagDecl *D, QualType can) 
-    : Type(TC, can, /*Dependent=*/false), decl(D, 0) {}
+  TagType(TypeClass TC, TagDecl *D, QualType can);
 
 public:   
   TagDecl *getDecl() const { return decl.getPointer(); }

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sun May 10 17:57:19 2009
@@ -1703,11 +1703,39 @@
                               VAT->getIndexTypeQualifier());
 }
 
+Decl *ASTContext::getCanonicalDecl(Decl *D) {
+  if (TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+    QualType T = getTagDeclType(Tag);
+    return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType)
+                         ->getDecl());
+  }
+
+  if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) {
+    while (Template->getPreviousDeclaration())
+      Template = Template->getPreviousDeclaration();
+    return Template;
+  }
+
+  if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+    while (Function->getPreviousDeclaration())
+      Function = Function->getPreviousDeclaration();
+    return const_cast<FunctionDecl *>(Function);
+  }
+
+  if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+    while (Var->getPreviousDeclaration())
+      Var = Var->getPreviousDeclaration();
+    return const_cast<VarDecl *>(Var);
+  }
+
+  return D;
+}
+
 TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
   // If this template name refers to a template, the canonical
   // template name merely stores the template itself.
   if (TemplateDecl *Template = Name.getAsTemplateDecl())
-    return TemplateName(Template);
+    return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template)));
 
   DependentTemplateName *DTN = Name.getAsDependentTemplateName();
   assert(DTN && "Non-dependent template names must refer to template decls.");

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sun May 10 17:57:19 2009
@@ -14,6 +14,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/Expr.h"
@@ -505,6 +506,18 @@
 // TagDecl Implementation
 //===----------------------------------------------------------------------===//
 
+bool TagDecl::isDependentType() const {
+  if (isa<TemplateDecl>(this))
+    return true;
+
+  if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(getDeclContext()))
+    return TD->isDependentType();
+
+  // FIXME: Tag types declared function templates are dependent types.
+  // FIXME: Look through block scopes.
+  return false;
+}
+
 void TagDecl::startDefinition() {
   TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType());
   TagT->decl.setPointer(this);

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Sun May 10 17:57:19 2009
@@ -120,6 +120,65 @@
   C.Deallocate((void*)this);
 }
 
+QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
+  if (!CommonPtr->InjectedClassNameType.isNull())
+    return CommonPtr->InjectedClassNameType;
+
+  // FIXME: n2800 14.6.1p1 should say how the template arguments
+  // corresponding to template parameter packs should be pack
+  // expansions. We already say that in 14.6.2.1p2, so it would be
+  // better to fix that redundancy.
+
+  TemplateParameterList *Params = getTemplateParameters();
+
+  llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+  llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs;
+  TemplateArgs.reserve(Params->size());
+  CanonTemplateArgs.reserve(Params->size());
+
+  for (TemplateParameterList::iterator 
+         Param = Params->begin(), ParamEnd = Params->end(); 
+       Param != ParamEnd; ++Param) {
+    if (isa<TemplateTypeParmDecl>(*Param)) {
+      QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
+      TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), 
+                                              ParamType));
+      CanonTemplateArgs.push_back(
+                         TemplateArgument((*Param)->getLocation(),
+                                          Context.getCanonicalType(ParamType)));
+    } else if (NonTypeTemplateParmDecl *NTTP = 
+                 dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+      // FIXME: Build canonical expression, too!
+      Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
+                                          NTTP->getLocation(),
+                                          NTTP->getType()->isDependentType(),
+                                          /*Value-dependent=*/true);
+      TemplateArgs.push_back(TemplateArgument(E));
+      CanonTemplateArgs.push_back(TemplateArgument(E));
+    } else { 
+      TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
+      TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP));
+      CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), 
+                                              Context.getCanonicalDecl(TTP)));
+    }
+  }
+
+  // FIXME: I should really move the "build-the-canonical-type" logic
+  // into ASTContext::getTemplateSpecializationType.
+  TemplateName Name = TemplateName(this);
+  QualType CanonType = Context.getTemplateSpecializationType(
+                                       Context.getCanonicalTemplateName(Name),
+                                             &CanonTemplateArgs[0],
+                                             CanonTemplateArgs.size());
+
+  CommonPtr->InjectedClassNameType
+    = Context.getTemplateSpecializationType(Name,
+                                            &TemplateArgs[0],
+                                            TemplateArgs.size(),
+                                            CanonType);
+  return CommonPtr->InjectedClassNameType;
+}
+
 //===----------------------------------------------------------------------===//
 // TemplateTypeParm Allocation/Deallocation Method Implementations
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Sun May 10 17:57:19 2009
@@ -1000,6 +1000,9 @@
   assert(!isa<TypedefType>(can) && "Invalid canonical type");
 }
 
+TagType::TagType(TypeClass TC, TagDecl *D, QualType can) 
+  : Type(TC, can, D->isDependentType()), decl(D, 0) {}
+
 bool RecordType::classof(const TagType *TT) {
   return isa<RecordDecl>(TT->getDecl());
 }

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun May 10 17:57:19 2009
@@ -123,8 +123,23 @@
     if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) {
       // Check whether we can use this type
       (void)DiagnoseUseOfDecl(IIDecl, NameLoc);
-      
-      T = Context.getTypeDeclType(TD);
+  
+      if (getLangOptions().CPlusPlus) {
+        // C++ [temp.local]p2:
+        //   Within the scope of a class template specialization or
+        //   partial specialization, when the injected-class-name is
+        //   not followed by a <, it is equivalent to the
+        //   injected-class-name followed by the template-argument s
+        //   of the class template specialization or partial
+        //   specialization enclosed in <>.
+        if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD))
+          if (RD->isInjectedClassName())
+            if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate())
+              T = Template->getInjectedClassNameType(Context);
+      }
+
+      if (T.isNull())
+        T = Context.getTypeDeclType(TD);
     } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) {
       // Check whether we can use this interface.
       (void)DiagnoseUseOfDecl(IIDecl, NameLoc);

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun May 10 17:57:19 2009
@@ -503,7 +503,7 @@
             PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0))
     Invalid = true;
     
-  // If we had a scope specifier, we better have a previous template
+  // FIXME: If we had a scope specifier, we better have a previous template
   // declaration!
 
   CXXRecordDecl *NewClass = 
@@ -749,8 +749,9 @@
       break;
 
     case TemplateArgument::Declaration:
-      Canonical.push_back(TemplateArgument(SourceLocation(),
-                                           TemplateArgs[Idx].getAsDecl()));
+      Canonical.push_back(
+                 TemplateArgument(SourceLocation(),
+                    Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl())));
       break;
 
     case TemplateArgument::Integral:
@@ -1124,10 +1125,9 @@
             Invalid = true;
           
           // Add the converted template argument.
-          // FIXME: Need the "canonical" template declaration!
-          Converted.push_back(
-                    TemplateArgument(Arg.getLocation(),
-                                     cast<DeclRefExpr>(ArgExpr)->getDecl()));
+          Decl *D 
+            = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl());
+          Converted.push_back(TemplateArgument(Arg.getLocation(), D));
           continue;
         }
       }
@@ -1549,8 +1549,10 @@
       if (CheckTemplateArgumentPointerToMember(Arg, Member))
         return true;
 
-      if (Converted)
+      if (Converted) {
+        Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
         Converted->push_back(TemplateArgument(StartLoc, Member));
+      }
 
       return false;
     }
@@ -1559,8 +1561,10 @@
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    if (Converted)
+    if (Converted) {
+      Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
       Converted->push_back(TemplateArgument(StartLoc, Entity));
+    }
     return false;
   }
 
@@ -1598,8 +1602,10 @@
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    if (Converted)
+    if (Converted) {
+      Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
       Converted->push_back(TemplateArgument(StartLoc, Entity));
+    }
 
     return false;
   }
@@ -1640,8 +1646,10 @@
     if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
       return true;
 
-    if (Converted)
+    if (Converted) {
+      Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity));
       Converted->push_back(TemplateArgument(StartLoc, Entity));
+    }
 
     return false;
   }
@@ -1670,9 +1678,11 @@
   if (CheckTemplateArgumentPointerToMember(Arg, Member))
     return true;
   
-  if (Converted)
+  if (Converted) {
+    Member = cast<NamedDecl>(Context.getCanonicalDecl(Member));
     Converted->push_back(TemplateArgument(StartLoc, Member));
-  
+  }
+
   return false;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sun May 10 17:57:19 2009
@@ -273,11 +273,8 @@
                             D->getLocation(), D->getIdentifier(), PrevDecl);
   Record->setImplicit(D->isImplicit());
   Record->setAccess(D->getAccess());
-
   if (!D->isInjectedClassName())
     Record->setInstantiationOfMemberClass(D);
-  else
-    Record->setDescribedClassTemplate(D->getDescribedClassTemplate());
 
   Owner->addDecl(SemaRef.Context, Record);
   return Record;

Modified: cfe/trunk/test/SemaTemplate/injected-class-name.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/injected-class-name.cpp?rev=71408&r1=71407&r2=71408&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/injected-class-name.cpp (original)
+++ cfe/trunk/test/SemaTemplate/injected-class-name.cpp Sun May 10 17:57:19 2009
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-
 template<typename T>
 struct X {
   X<T*> *ptr;
@@ -13,5 +12,29 @@
 };
 
 // FIXME: EDG rejects this in their strict-conformance mode, but I
-// don't see any wording making this ill-formed.
+// don't see any wording making this ill-formed.  Actually,
+// [temp.local]p2 might make it ill-formed. Are we "in the scope of
+// the class template specialization?"
 X<float>::X<int> xi = x;
+
+// [temp.local]p1:
+
+// FIXME: test non-type and template template parameters
+template<typename T, typename U>
+struct X0 {
+  typedef T type;
+  typedef U U_type;
+  typedef U_type U_type2;
+
+  void f0(const X0&); // expected-note{{here}}
+  void f0(X0&);
+  void f0(const X0<T, U>&); // expected-error{{redecl}}
+
+  void f1(const X0&); // expected-note{{here}}
+  void f1(X0&);
+  void f1(const X0<type, U_type2>&); // expected-error{{redecl}}
+
+  void f2(const X0&); // expected-note{{here}}
+  void f2(X0&);
+  void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}}
+};





More information about the cfe-commits mailing list