[cfe-commits] r101029 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/default-expr-arguments-2.cpp test/SemaTemplate/instantiate-method.cpp

Douglas Gregor dgregor at apple.com
Mon Apr 12 00:48:19 PDT 2010


Author: dgregor
Date: Mon Apr 12 02:48:19 2010
New Revision: 101029

URL: http://llvm.org/viewvc/llvm-project?rev=101029&view=rev
Log:
Be sure to instantiate the parameters of a function, even when the
function's type is (strictly speaking) non-dependent. This ensures
that, e.g., default function arguments get instantiated properly.

And, since I couldn't resist, collapse the two implementations of
function-parameter instantiation into calls to a single, new function
(Sema::SubstParmVarDecl), since the two had nearly identical code (and
each had bugs the other didn't!). More importantly, factored out the
semantic analysis of a parameter declaration into
Sema::CheckParameter, which is called both by
Sema::ActOnParamDeclarator (when parameters are parsed) and when a
parameter is instantiated. Previously, we were missing some
Objective-C and address-space checks on instantiated function
parameters.

Fixes PR6733.


Added:
    cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp   (with props)
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/SemaTemplate/instantiate-method.cpp

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=101029&r1=101028&r2=101029&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Apr 12 02:48:19 2010
@@ -805,6 +805,11 @@
                                 bool &OverloadableAttrRequired);
   void CheckMain(FunctionDecl *FD);
   virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
+  ParmVarDecl *CheckParameter(DeclContext *DC, 
+                              TypeSourceInfo *TSInfo, QualType T,
+                              IdentifierInfo *Name,
+                              SourceLocation NameLoc,
+                              VarDecl::StorageClass StorageClass);
   virtual void ActOnObjCCatchParam(DeclPtrTy D);
   virtual void ActOnParamDefaultArgument(DeclPtrTy param,
                                          SourceLocation EqualLoc,
@@ -3642,7 +3647,8 @@
                             const MultiLevelTemplateArgumentList &TemplateArgs,
                                         SourceLocation Loc,
                                         DeclarationName Entity);
-
+  ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, 
+                            const MultiLevelTemplateArgumentList &TemplateArgs);
   OwningExprResult SubstExpr(Expr *E,
                             const MultiLevelTemplateArgumentList &TemplateArgs);
 
@@ -3710,8 +3716,6 @@
   DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
                           const MultiLevelTemplateArgumentList &TemplateArgs);
 
-  bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params);
-
   // Objective-C declarations.
   virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
                                              IdentifierInfo *ClassName,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=101029&r1=101028&r2=101029&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Apr 12 02:48:19 2010
@@ -4118,55 +4118,23 @@
     }
   }
 
-  // Parameters can not be abstract class types.
-  // For record types, this is done by the AbstractClassUsageDiagnoser once
-  // the class has been completely parsed.
-  if (!CurContext->isRecord() &&
-      RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
-                             diag::err_abstract_type_in_decl,
-                             AbstractParamType))
-    D.setInvalidType(true);
-
-  QualType T = adjustParameterType(parmDeclType);
-
   // Temporarily put parameter variables in the translation unit, not
   // the enclosing context.  This prevents them from accidentally
   // looking like class members in C++.
-  DeclContext *DC = Context.getTranslationUnitDecl();
-
-  ParmVarDecl *New
-    = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
-                          T, TInfo, StorageClass, 0);
+  ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
+                                    TInfo, parmDeclType, II, 
+                                    D.getIdentifierLoc(), StorageClass);
 
   if (D.isInvalidType())
-    New->setInvalidDecl();
-
-  // Parameter declarators cannot be interface types. All ObjC objects are
-  // passed by reference.
-  if (T->isObjCInterfaceType()) {
-    Diag(D.getIdentifierLoc(),
-         diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
-    New->setInvalidDecl();
-  }
-
+    New->setInvalidDecl();  
+  
   // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
   if (D.getCXXScopeSpec().isSet()) {
     Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
       << D.getCXXScopeSpec().getRange();
     New->setInvalidDecl();
   }
-  
-  // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage 
-  // duration shall not be qualified by an address-space qualifier."
-  // Since all parameters have automatic store duration, they can not have
-  // an address space.
-  if (T.getAddressSpace() != 0) {
-    Diag(D.getIdentifierLoc(),  
-         diag::err_arg_with_address_space);
-    New->setInvalidDecl();
-  }   
-  
-  
+
   // Add the parameter declaration into this scope.
   S->AddDecl(DeclPtrTy::make(New));
   if (II)
@@ -4180,6 +4148,43 @@
   return DeclPtrTy::make(New);
 }
 
+ParmVarDecl *Sema::CheckParameter(DeclContext *DC, 
+                                  TypeSourceInfo *TSInfo, QualType T,
+                                  IdentifierInfo *Name,
+                                  SourceLocation NameLoc,
+                                  VarDecl::StorageClass StorageClass) {
+  ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
+                                         adjustParameterType(T), TSInfo, 
+                                         StorageClass, 0);
+
+  // Parameters can not be abstract class types.
+  // For record types, this is done by the AbstractClassUsageDiagnoser once
+  // the class has been completely parsed.
+  if (!CurContext->isRecord() &&
+      RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl,
+                             AbstractParamType))
+    New->setInvalidDecl();
+
+  // Parameter declarators cannot be interface types. All ObjC objects are
+  // passed by reference.
+  if (T->isObjCInterfaceType()) {
+    Diag(NameLoc,
+         diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
+    New->setInvalidDecl();
+  }
+
+  // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage 
+  // duration shall not be qualified by an address-space qualifier."
+  // Since all parameters have automatic store duration, they can not have
+  // an address space.
+  if (T.getAddressSpace() != 0) {
+    Diag(NameLoc, diag::err_arg_with_address_space);
+    New->setInvalidDecl();
+  }   
+
+  return New;
+}
+
 void Sema::ActOnObjCCatchParam(DeclPtrTy D) {
   ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>());
   Param->setDeclContext(CurContext);

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=101029&r1=101028&r2=101029&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Apr 12 02:48:19 2010
@@ -807,47 +807,12 @@
         TransformFunctionTypeParams(TL, PTypes, PVars))
     return true;
 
-  // Check instantiated parameters.
-  if (SemaRef.CheckInstantiatedParams(PVars))
-    return true;
-
   return false;
 }
 
 ParmVarDecl *
 TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
-  TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
-  TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
-  if (!NewDI)
-    return 0;
-
-  // TODO: do we have to clone this decl if the types match and
-  // there's no default argument?
-
-  ParmVarDecl *NewParm
-    = ParmVarDecl::Create(SemaRef.Context,
-                          OldParm->getDeclContext(),
-                          OldParm->getLocation(),
-                          OldParm->getIdentifier(),
-                          NewDI->getType(),
-                          NewDI,
-                          OldParm->getStorageClass(),
-                          /* DefArg */ NULL);
-
-  // Maybe adjust new parameter type.
-  NewParm->setType(SemaRef.adjustParameterType(NewParm->getType()));
-
-  // Mark the (new) default argument as uninstantiated (if any).
-  if (OldParm->hasUninstantiatedDefaultArg()) {
-    Expr *Arg = OldParm->getUninstantiatedDefaultArg();
-    NewParm->setUninstantiatedDefaultArg(Arg);
-  } else if (Expr *Arg = OldParm->getDefaultArg())
-    NewParm->setUninstantiatedDefaultArg(Arg);
-
-  NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
-
-  SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
-  return NewParm;
+  return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs);
 }
 
 QualType
@@ -1009,6 +974,40 @@
   return TLB.getTypeSourceInfo(Context, Result);
 }
 
+ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, 
+                          const MultiLevelTemplateArgumentList &TemplateArgs) {
+  TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
+  TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
+                                    OldParm->getDeclName());
+  if (!NewDI)
+    return 0;
+
+  if (NewDI->getType()->isVoidType()) {
+    Diag(OldParm->getLocation(), diag::err_param_with_void_type);
+    return 0;
+  }
+
+  ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
+                                        NewDI, NewDI->getType(),
+                                        OldParm->getIdentifier(),
+                                        OldParm->getLocation(),
+                                        OldParm->getStorageClass());
+  if (!NewParm)
+    return 0;
+                                                
+  // Mark the (new) default argument as uninstantiated (if any).
+  if (OldParm->hasUninstantiatedDefaultArg()) {
+    Expr *Arg = OldParm->getUninstantiatedDefaultArg();
+    NewParm->setUninstantiatedDefaultArg(Arg);
+  } else if (Expr *Arg = OldParm->getDefaultArg())
+    NewParm->setUninstantiatedDefaultArg(Arg);
+
+  NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
+
+  CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
+  return NewParm;  
+}
+
 /// \brief Perform substitution on the base class specifiers of the
 /// given class template specialization.
 ///

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=101029&r1=101028&r2=101029&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Apr 12 02:48:19 2010
@@ -1343,41 +1343,7 @@
 }
 
 ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
-  QualType T;
-  TypeSourceInfo *DI = D->getTypeSourceInfo();
-  if (DI) {
-    DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
-                           D->getDeclName());
-    if (DI) T = DI->getType();
-  } else {
-    T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(),
-                          D->getDeclName());
-    DI = 0;
-  }
-
-  if (T.isNull())
-    return 0;
-
-  T = SemaRef.adjustParameterType(T);
-
-  // Allocate the parameter
-  ParmVarDecl *Param
-    = ParmVarDecl::Create(SemaRef.Context,
-                          SemaRef.Context.getTranslationUnitDecl(),
-                          D->getLocation(),
-                          D->getIdentifier(), T, DI, D->getStorageClass(), 0);
-
-  // Mark the default argument as being uninstantiated.
-  if (D->hasUninstantiatedDefaultArg())
-    Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
-  else if (Expr *Arg = D->getDefaultArg())
-    Param->setUninstantiatedDefaultArg(Arg);
-  
-  // Note: we don't try to instantiate function parameters until after
-  // we've instantiated the function's type. Therefore, we don't have
-  // to check for 'void' parameter types here.
-  SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
-  return Param;
+  return SemaRef.SubstParmVarDecl(D, TemplateArgs);
 }
 
 Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@@ -1797,29 +1763,6 @@
   return false;
 }
 
-bool
-Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) {
-  bool Invalid = false;
-  for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i)
-    if (ParmVarDecl *PInst = Params[i]) {
-      if (PInst->isInvalidDecl())
-        Invalid = true;
-      else if (PInst->getType()->isVoidType()) {
-        Diag(PInst->getLocation(), diag::err_param_with_void_type);
-        PInst->setInvalidDecl();
-        Invalid = true;
-      }
-      else if (RequireNonAbstractType(PInst->getLocation(),
-                                      PInst->getType(),
-                                      diag::err_abstract_type_in_decl,
-                                      Sema::AbstractParamType)) {
-        PInst->setInvalidDecl();
-        Invalid = true;
-      }
-    }
-  return Invalid;
-}
-
 TypeSourceInfo*
 TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
                               llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
@@ -1833,13 +1776,26 @@
   if (!NewTInfo)
     return 0;
 
-  // Get parameters from the new type info.
-  TypeLoc NewTL = NewTInfo->getTypeLoc();
-  FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
-  assert(NewProtoLoc && "Missing prototype?");
-  for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
-    Params.push_back(NewProtoLoc->getArg(i));
-
+  if (NewTInfo != OldTInfo) {
+    // Get parameters from the new type info.
+    TypeLoc NewTL = NewTInfo->getTypeLoc();
+    FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
+    assert(NewProtoLoc && "Missing prototype?");
+    for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
+      Params.push_back(NewProtoLoc->getArg(i));
+  } else {
+    // The function type itself was not dependent and therefore no
+    // substitution occurred. However, we still need to instantiate
+    // the function parameters themselves.
+    TypeLoc OldTL = OldTInfo->getTypeLoc();
+    FunctionProtoTypeLoc *OldProtoLoc = cast<FunctionProtoTypeLoc>(&OldTL);
+    for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
+      ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
+      if (!Parm)
+        return 0;
+      Params.push_back(Parm);
+    }
+  }
   return NewTInfo;
 }
 

Added: cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp?rev=101029&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp (added)
+++ cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp Mon Apr 12 02:48:19 2010
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
+
+// This is a wacky test to ensure that we're actually instantiating
+// the default rguments of the constructor when the function type is
+// otherwise non-dependent.
+namespace PR6733 {
+  template <class T>
+  class bar {
+  public: enum { kSomeConst = 128 };
+    bar(int x = kSomeConst) {}
+  };
+  
+  // CHECK: void f()
+  void f() {
+    // CHECK: bar<int> tmp =
+    // CHECK: CXXDefaultArgExpr{{.*}}'int'
+    bar<int> tmp;
+  }
+}

Propchange: cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaTemplate/default-expr-arguments-2.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaTemplate/instantiate-method.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-method.cpp?rev=101029&r1=101028&r2=101029&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-method.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-method.cpp Mon Apr 12 02:48:19 2010
@@ -5,7 +5,7 @@
   void f(T x); // expected-error{{argument may not have 'void' type}}
   void g(T*);
 
-  static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
+  static int h(T, T); // expected-error {{argument may not have 'void' type}}
 };
 
 int identity(int x) { return x; }





More information about the cfe-commits mailing list