[cfe-commits] r64185 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.def include/clang/Parse/Action.h include/clang/Parse/Ownership.h include/clang/Parse/Parser.h lib/AST/Type.cpp lib/Parse/ParseTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/temp_arg.cpp test/SemaTemplate/temp_arg_type.cpp

Douglas Gregor dgregor at apple.com
Mon Feb 9 15:23:09 PST 2009


Author: dgregor
Date: Mon Feb  9 17:23:08 2009
New Revision: 64185

URL: http://llvm.org/viewvc/llvm-project?rev=64185&view=rev
Log:
Rudimentary checking of template arguments against their corresponding
template parameters when performing semantic analysis of a template-id
naming a class template specialization.

Added:
    cfe/trunk/test/SemaTemplate/temp_arg.cpp
    cfe/trunk/test/SemaTemplate/temp_arg_type.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Ownership.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Mon Feb  9 17:23:08 2009
@@ -464,7 +464,7 @@
 DIAG(err_member_call_without_object, ERROR,
      "call to non-static member function without an object argument")
 
-/// C++ Templates Semantic Analysis
+// C++ Template Declarations
 DIAG(err_template_param_shadow, ERROR,
      "declaration of %0 shadows template parameter")
 DIAG(note_template_param_here, NOTE,
@@ -488,6 +488,26 @@
 DIAG(note_template_nontype_parm_prev_declaration, NOTE,
      "previous non-type template parameter with type %0 is here")
 
+// C++ Template Argument Lists
+DIAG(err_template_arg_list_different_arity, ERROR,
+     "%select{too few|too many}0 template arguments for %select{class template|function template|template template parameter|template}1 %2")
+DIAG(note_template_parameter_here, ERROR,
+     "template parameter is declared here")
+DIAG(err_template_arg_must_be_type, ERROR,
+     "template argument for template type parameter must be a type")
+DIAG(err_template_arg_must_be_expr, ERROR,
+     "template argument for non-type template parameter must be an expression")
+DIAG(err_template_arg_nontype_ambig, ERROR,
+     "template argument for non-type template parameter is treated as type %0")
+DIAG(err_template_arg_must_be_template, ERROR,
+     "template argument for template template parameter must be a template")
+DIAG(err_template_arg_local_type, ERROR,
+     "template argument uses local type %0")
+DIAG(err_template_arg_unnamed_type, ERROR,
+     "template argument uses unnamed type")
+DIAG(note_template_unnamed_type_here, NOTE,
+     "unnamed type used in template argument was declared here")
+
 DIAG(err_unexpected_typedef, ERROR,
      "unexpected type name %0: expected expression")
 DIAG(err_unexpected_namespace, ERROR,

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Mon Feb  9 17:23:08 2009
@@ -1134,8 +1134,10 @@
   /// new class template specialization.
   virtual TypeTy * 
   ActOnClassTemplateSpecialization(DeclTy *Template,
+                                   SourceLocation TemplateLoc,
                                    SourceLocation LAngleLoc,
                                    ASTTemplateArgsPtr TemplateArgs,
+                                   SourceLocation *TemplateArgLocs,
                                    SourceLocation RAngleLoc,
                                    const CXXScopeSpec *SS = 0) {
     return 0;

Modified: cfe/trunk/include/clang/Parse/Ownership.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Ownership.h?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Ownership.h (original)
+++ cfe/trunk/include/clang/Parse/Ownership.h Mon Feb  9 17:23:08 2009
@@ -567,7 +567,7 @@
 #endif
       Args(Other.Args), ArgIsType(Other.ArgIsType), Count(Other.Count) {
 #if !defined(DISABLE_SMART_POINTERS)
-      Other.destroy();
+      Other.Count = 0;
 #endif
     }
 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Feb  9 17:23:08 2009
@@ -1007,10 +1007,12 @@
   // C++ 14.3: Template arguments [temp.arg]
   typedef llvm::SmallVector<void *, 16> TemplateArgList;
   typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList;
+  typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList;
   void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
                                const CXXScopeSpec *SS = 0);
   bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
-                                 TemplateArgIsTypeList &TemplateArgIsType);
+                                 TemplateArgIsTypeList &TemplateArgIsType,
+                                 TemplateArgLocationList &TemplateArgLocations);
   void *ParseTemplateArgument(bool &ArgIsType);
 
   //===--------------------------------------------------------------------===//

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

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Feb  9 17:23:08 2009
@@ -943,7 +943,7 @@
   const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
   const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
   Data += Arg / BitsPerWord;
-  return (*Data >> (Arg % BitsPerWord)) & 0x01;
+  return (*Data >> ((NumArgs - Arg) % BitsPerWord - 1)) & 0x01;
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Mon Feb  9 17:23:08 2009
@@ -370,10 +370,13 @@
   // Parse the optional template-argument-list.
   TemplateArgList TemplateArgs;
   TemplateArgIsTypeList TemplateArgIsType;
+  TemplateArgLocationList TemplateArgLocations;
+
   {
     GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
     if (Tok.isNot(tok::greater) && 
-        ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType)) {
+        ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
+                                  TemplateArgLocations)) {
       // Try to find the closing '>'.
       SkipUntil(tok::greater, true, true);
 
@@ -417,9 +420,14 @@
                                        &TemplateArgIsType[0],
                                        TemplateArgs.size());
     TypeTy *Ty 
-      = Actions.ActOnClassTemplateSpecialization(Template, LAngleLoc,
-                                                 TemplateArgsPtr,
+      = Actions.ActOnClassTemplateSpecialization(Template, TemplateNameLoc,
+                                                 LAngleLoc, TemplateArgsPtr,
+                                                 &TemplateArgLocations[0],
                                                  RAngleLoc, SS);
+
+    if (!Ty) // Something went wrong; don't annotate
+      return;
+
     Tok.setKind(tok::annot_typename);
     Tok.setAnnotationValue(Ty);
   }
@@ -453,8 +461,8 @@
     return ParseTypeName();
   }
 
-  OwningExprResult ExprArg = ParseExpression();
-  if (ExprArg.isInvalid())
+  OwningExprResult ExprArg = ParseAssignmentExpression();
+  if (ExprArg.isInvalid() || !ExprArg.get())
     return 0;
 
   ArgIsType = false;
@@ -469,13 +477,16 @@
 ///         template-argument-list ',' template-argument
 bool 
 Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
-                                  TemplateArgIsTypeList &TemplateArgIsType) {
+                                  TemplateArgIsTypeList &TemplateArgIsType,
+                              TemplateArgLocationList &TemplateArgLocations) {
   while (true) {
     bool IsType = false;
+    SourceLocation Loc = Tok.getLocation();
     void *Arg = ParseTemplateArgument(IsType);
     if (Arg) {
       TemplateArgs.push_back(Arg);
       TemplateArgIsType.push_back(IsType);
+      TemplateArgLocations.push_back(Loc);
     } else {
       SkipUntil(tok::comma, tok::greater, true, true);
       return true;

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64185&r1=64184&r2=64185&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb  9 17:23:08 2009
@@ -62,6 +62,7 @@
   class TypedefDecl;
   class TemplateDecl;
   class TemplateParameterList;
+  class TemplateTemplateParmDecl;
   class ObjCInterfaceDecl;
   class ObjCCompatibleAliasDecl;
   class ObjCProtocolDecl;
@@ -1515,12 +1516,25 @@
                      MultiTemplateParamsArg TemplateParameterLists);
 
   virtual TypeTy * 
-  ActOnClassTemplateSpecialization(DeclTy *Template,
+  ActOnClassTemplateSpecialization(DeclTy *Template, 
+                                   SourceLocation TemplateLoc,
                                    SourceLocation LAngleLoc,
                                    ASTTemplateArgsPtr TemplateArgs,
+                                   SourceLocation *TemplateArgLocs,
                                    SourceLocation RAngleLoc,
                                    const CXXScopeSpec *SS = 0);
 
+  bool CheckTemplateArgumentList(TemplateDecl *Template,
+                                 SourceLocation TemplateLoc,
+                                 SourceLocation LAngleLoc,
+                                 ASTTemplateArgsPtr& TemplateArgs,
+                                 SourceLocation *TemplateArgLocs,
+                                 SourceLocation RAngleLoc);
+
+  bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
+                             SourceLocation ArgLoc);
+  bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *Arg);
+  bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
   bool TemplateParameterListsAreEqual(TemplateParameterList *New,
                                       TemplateParameterList *Old,
                                       bool Complain,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Feb  9 17:23:08 2009
@@ -746,7 +746,9 @@
   if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
     return Owned(BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc,
                                   false, false, SS));
-
+  else if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D))
+    return Owned(BuildDeclRefExpr(Template, Context.OverloadTy, Loc,
+                                  false, false, SS));
   ValueDecl *VD = cast<ValueDecl>(D);
 
   // check if referencing an identifier with __attribute__((deprecated)).

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb  9 17:23:08 2009
@@ -356,14 +356,24 @@
   return NewTemplate;
 }
 
+
+
 Action::TypeTy * 
 Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
+                                       SourceLocation TemplateLoc,
                                        SourceLocation LAngleLoc,
                                        ASTTemplateArgsPtr TemplateArgs,
+                                       SourceLocation *TemplateArgLocs,
                                        SourceLocation RAngleLoc,
                                        const CXXScopeSpec *SS) {
   TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
 
+  // Check that the template argument list is well-formed for this
+  // template.
+  if (!CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, 
+                                 TemplateArgs, TemplateArgLocs, RAngleLoc))
+    return 0;
+
   // Yes, all class template specializations are just silly sugar for
   // 'int'. Gotta problem wit dat?
   QualType Result
@@ -376,6 +386,178 @@
   return Result.getAsOpaquePtr();
 }
 
+/// \brief Check that the given template argument list is well-formed
+/// for specializing the given template.
+bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
+                                     SourceLocation TemplateLoc,
+                                     SourceLocation LAngleLoc,
+                                     ASTTemplateArgsPtr& Args,
+                                     SourceLocation *TemplateArgLocs,
+                                     SourceLocation RAngleLoc) {
+  TemplateParameterList *Params = Template->getTemplateParameters();
+  unsigned NumParams = Params->size();
+  unsigned NumArgs = Args.size();
+  bool Invalid = false;
+
+  if (NumArgs > NumParams ||
+      NumArgs < NumParams /*FIXME: default arguments! */) {
+    // FIXME: point at either the first arg beyond what we can handle,
+    // or the '>', depending on whether we have too many or too few
+    // arguments.
+    SourceRange Range;
+    if (NumArgs > NumParams)
+      Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc);
+    Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+      << (NumArgs > NumParams)
+      << (isa<ClassTemplateDecl>(Template)? 0 :
+          isa<FunctionTemplateDecl>(Template)? 1 :
+          isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
+      << Template << Range;
+
+    Invalid = true;
+  }
+  
+  // C++ [temp.arg]p1: 
+  //   [...] The type and form of each template-argument specified in
+  //   a template-id shall match the type and form specified for the
+  //   corresponding parameter declared by the template in its
+  //   template-parameter-list.
+  unsigned ArgIdx = 0;
+  for (TemplateParameterList::iterator Param = Params->begin(),
+                                       ParamEnd = Params->end();
+       Param != ParamEnd; ++Param, ++ArgIdx) {
+    // Decode the template argument
+    QualType ArgType;
+    Expr *ArgExpr = 0;
+    SourceLocation ArgLoc;
+    if (ArgIdx >= NumArgs) {
+      // FIXME: Get the default argument here, which might
+      // (eventually) require instantiation.
+      break;
+    } else
+      ArgLoc = TemplateArgLocs[ArgIdx];
+
+    if (Args.getArgIsType()[ArgIdx])
+      ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
+    else
+      ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
+
+    if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+      // Check template type parameters.
+      if (!ArgType.isNull()) {
+        if (!CheckTemplateArgument(TTP, ArgType, ArgLoc))
+          Invalid = true;
+        continue;
+      }
+
+      // C++ [temp.arg.type]p1:
+      //   A template-argument for a template-parameter which is a
+      //   type shall be a type-id.
+
+      // We have a template type parameter but the template argument
+      // is an expression.
+      Diag(ArgExpr->getSourceRange().getBegin(), 
+           diag::err_template_arg_must_be_type);
+      Diag((*Param)->getLocation(), diag::note_template_parameter_here);
+      Invalid = true;
+    } else if (NonTypeTemplateParmDecl *NTTP 
+                 = dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
+      // Check non-type template parameters.
+      if (ArgExpr) {
+        if (!CheckTemplateArgument(NTTP, ArgExpr))
+          Invalid = true;
+        continue;
+      }
+
+      // We have a non-type template parameter but the template
+      // argument is a type.
+
+      // C++ [temp.arg]p2:
+      //   In a template-argument, an ambiguity between a type-id and
+      //   an expression is resolved to a type-id, regardless of the
+      //   form of the corresponding template-parameter.
+      //
+      // We warn specifically about this case, since it can be rather
+      // confusing for users.
+      if (ArgType->isFunctionType())
+        Diag(ArgLoc, diag::err_template_arg_nontype_ambig)
+          << ArgType;
+      else
+        Diag(ArgLoc, diag::err_template_arg_must_be_expr);
+      Diag((*Param)->getLocation(), diag::note_template_parameter_here);
+      Invalid = true;
+    } else { 
+      // Check template template parameters.
+      TemplateTemplateParmDecl *TempParm 
+        = cast<TemplateTemplateParmDecl>(*Param);
+     
+      if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
+          isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
+        if (!CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
+          Invalid = true;
+        continue;
+      }
+
+      // We have a template template parameter but the template
+      // argument does not refer to a template.
+      Diag(ArgLoc, diag::err_template_arg_must_be_template);
+      Invalid = true;
+    }
+  }
+
+  return Invalid;
+}
+
+/// \brief Check a template argument against its corresponding
+/// template type parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.type]. It
+/// returns true if an error occurred, and false otherwise.
+bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, 
+                                 QualType Arg, SourceLocation ArgLoc) {
+  // C++ [temp.arg.type]p2:
+  //   A local type, a type with no linkage, an unnamed type or a type
+  //   compounded from any of these types shall not be used as a
+  //   template-argument for a template type-parameter.
+  //
+  // FIXME: Perform the recursive and no-linkage type checks.
+  const TagType *Tag = 0;
+  if (const EnumType *EnumT = Arg->getAsEnumType())
+    Tag = EnumT;
+  else if (const RecordType *RecordT = Arg->getAsRecordType())
+    Tag = RecordT;
+  if (Tag && Tag->getDecl()->getDeclContext()->isFunctionOrMethod())
+    return Diag(ArgLoc, diag::err_template_arg_local_type)
+      << QualType(Tag, 0);
+  else if (Tag && !Tag->getDecl()->getDeclName()) {
+    Diag(ArgLoc, diag::err_template_arg_unnamed_type);
+    Diag(Tag->getDecl()->getLocation(), diag::note_template_unnamed_type_here);
+    return true;
+  }
+
+  return false;
+}
+
+/// \brief Check a template argument against its corresponding
+/// non-type template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.nontype]. 
+/// It returns true if an error occurred, and false otherwise.
+bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+                                 Expr *Arg) {
+  return false;
+}
+
+/// \brief Check a template argument against its corresponding
+/// template template parameter.
+///
+/// This routine implements the semantics of C++ [temp.arg.template].
+/// It returns true if an error occurred, and false otherwise.
+bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
+                                 DeclRefExpr *Arg) {
+  return false;
+}
+
 /// \brief Determine whether the given template parameter lists are
 /// equivalent.
 ///

Added: cfe/trunk/test/SemaTemplate/temp_arg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg.cpp?rev=64185&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_arg.cpp Mon Feb  9 17:23:08 2009
@@ -0,0 +1,13 @@
+// RUN: clang -fsyntax-only -verify %s
+template<typename T, 
+         int I, 
+         template<typename> class TT>
+  class A;
+
+template<typename> class X;
+
+A<int, 0, X> * a1;
+
+A<float, 1, X, double> *a2; // expected-error{{too many template arguments for class template 'A'}}
+
+A<float, 1> *a3; // expected-error{{too few template arguments for class template 'A'}}

Added: cfe/trunk/test/SemaTemplate/temp_arg_type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_type.cpp?rev=64185&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_type.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_arg_type.cpp Mon Feb  9 17:23:08 2009
@@ -0,0 +1,27 @@
+// RUN: clang -fsyntax-only -verify %s
+template<typename T> class A; // expected-error 2 {{template parameter is declared here}}
+
+// [temp.arg.type]p1
+A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}
+
+A<A> *a2; // expected-error{{template argument for template type parameter must be a type}}
+
+A<int> *a3;
+// FIXME: The two below are well-formed, but we're not parsing them as type-ids.
+// A<int()> *a4; 
+// A<int(float)> *a5;
+A<A<int> > *a6;
+
+// [temp.arg.type]p2
+void f() {
+  class X { };
+  A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}\
+                // FIXME: expected-error{{expected expression}}
+}
+
+struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
+A<__typeof__(Unnamed)> *a7; // expected-error{{template argument uses unnamed type}} \
+                            // FIXME: expected-error{{expected unqualified-id}}
+
+// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
+// belongs somewhere in the template instantiation section).





More information about the cfe-commits mailing list