[cfe-commits] r67575 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Sema/SemaType.cpp test/SemaCXX/nested-name-spec.cpp test/SemaTemplate/instantiate-method.cpp

Douglas Gregor dgregor at apple.com
Mon Mar 23 16:06:20 PDT 2009


Author: dgregor
Date: Mon Mar 23 18:06:20 2009
New Revision: 67575

URL: http://llvm.org/viewvc/llvm-project?rev=67575&view=rev
Log:
Template instantiation for the declarations of member functions within
a class template. At present, we can only instantiation normal
methods, but not constructors, destructors, or conversion operators.

As ever, this contains a bit of refactoring in Sema's type-checking. In
particular:

  - Split ActOnFunctionDeclarator into ActOnFunctionDeclarator
    (handling the declarator itself) and CheckFunctionDeclaration
    (checking for the the function declaration), the latter of which
    is also used by template instantiation.
  - We were performing the adjustment of function parameter types in
    three places; collect those into a single new routine.
  - When the type of a parameter is adjusted, allocate an
    OriginalParmVarDecl to keep track of the type as it was written.
  - Eliminate a redundant check for out-of-line declarations of member
    functions; hide more C++-specific checks on function declarations
    behind if(getLangOptions().CPlusPlus).


Added:
    cfe/trunk/test/SemaTemplate/instantiate-method.cpp
Modified:
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Mar 23 18:06:20 2009
@@ -290,6 +290,7 @@
   //===--------------------------------------------------------------------===//
   // Type Analysis / Processing: SemaType.cpp.
   //
+  QualType adjustParameterType(QualType T);
   QualType ConvertDeclSpecToType(const DeclSpec &DS);
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
   QualType BuildPointerType(QualType T, unsigned Quals, 
@@ -349,6 +350,9 @@
                                      NamedDecl* PrevDecl, 
                                      bool IsFunctionDefinition,
                                      bool& InvalidDecl, bool &Redeclaration);
+  bool CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+                                bool &Redeclaration, 
+                                bool &OverloadableAttrRequired);
   virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
   virtual void ActOnParamDefaultArgument(DeclTy *param,
                                          SourceLocation EqualLoc,

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar 23 18:06:20 2009
@@ -1437,7 +1437,7 @@
   // If there was a previous declaration of this variable, it may be
   // in our identifier chain. Update the identifier chain with the new
   // declaration.
-  if (IdResolver.ReplaceDecl(PrevDecl, ND)) {
+  if (S && IdResolver.ReplaceDecl(PrevDecl, ND)) {
     // The previous declaration was found on the identifer resolver
     // chain, so remove it from its scope.
     while (S && !S->isDeclScope(PrevDecl))
@@ -2034,23 +2034,6 @@
       NewFD->setParams(Context, &Params[0], Params.size());
     }
   }
-
-  if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
-    InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
-  else if (isa<CXXDestructorDecl>(NewFD)) {
-    CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
-    Record->setUserDeclaredDestructor(true);
-    // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
-    // user-defined destructor.
-    Record->setPOD(false);
-  } else if (CXXConversionDecl *Conversion =
-             dyn_cast<CXXConversionDecl>(NewFD))
-    ActOnConversionDeclarator(Conversion);
-
-  // Extra checking for C++ overloaded operators (C++ [over.oper]).
-  if (NewFD->isOverloadedOperator() &&
-      CheckOverloadedOperatorDeclaration(NewFD))
-    NewFD->setInvalidDecl();
     
   // If name lookup finds a previous declaration that is not in the
   // same scope as the new declaration, this may still be an
@@ -2060,19 +2043,130 @@
         isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
     PrevDecl = 0;
 
+  // Perform semantic checking on the function declaration.
+  bool OverloadableAttrRequired = false; // FIXME: HACK!
+  if (CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
+                               /*FIXME:*/OverloadableAttrRequired))
+    InvalidDecl = true;
+
+  if (D.getCXXScopeSpec().isSet() && !InvalidDecl) {
+    // An out-of-line member function declaration must also be a
+    // definition (C++ [dcl.meaning]p1).
+    if (!IsFunctionDefinition) {
+      Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
+        << D.getCXXScopeSpec().getRange();
+      InvalidDecl = true;
+    } else if (!Redeclaration) {
+      // The user tried to provide an out-of-line definition for a
+      // function that is a member of a class or namespace, but there
+      // was no such member function declared (C++ [class.mfct]p2, 
+      // C++ [namespace.memdef]p2). For example:
+      // 
+      // class X {
+      //   void f() const;
+      // }; 
+      //
+      // void X::f() { } // ill-formed
+      //
+      // Complain about this problem, and attempt to suggest close
+      // matches (e.g., those that differ only in cv-qualifiers and
+      // whether the parameter types are references).
+      Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
+        << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
+      InvalidDecl = true;
+      
+      LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, 
+                                              true);
+      assert(!Prev.isAmbiguous() && 
+             "Cannot have an ambiguity in previous-declaration lookup");
+      for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
+           Func != FuncEnd; ++Func) {
+        if (isa<FunctionDecl>(*Func) &&
+            isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
+          Diag((*Func)->getLocation(), diag::note_member_def_close_match);
+      }
+      
+      PrevDecl = 0;
+    }
+  }
+
+  // Handle attributes. We need to have merged decls when handling attributes
+  // (for example to check for conflicts, etc).
+  // FIXME: This needs to happen before we merge declarations. Then,
+  // let attribute merging cope with attribute conflicts.
+  ProcessDeclAttributes(NewFD, D);
+  AddKnownFunctionAttributes(NewFD);
+
+  if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
+    // If a function name is overloadable in C, then every function
+    // with that name must be marked "overloadable".
+    Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
+      << Redeclaration << NewFD;
+    if (PrevDecl)
+      Diag(PrevDecl->getLocation(), 
+           diag::note_attribute_overloadable_prev_overload);
+    NewFD->addAttr(::new (Context) OverloadableAttr());
+  }
+
+  // If this is a locally-scoped extern C function, update the
+  // map of such names.
+  if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
+      && !InvalidDecl)
+    RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
+
+  return NewFD;
+}
+
+/// \brief Perform semantic checking of a new function declaration.
+///
+/// Performs semantic analysis of the new function declaration
+/// NewFD. This routine performs all semantic checking that does not
+/// require the actual declarator involved in the declaration, and is
+/// used both for the declaration of functions as they are parsed
+/// (called via ActOnDeclarator) and for the declaration of functions
+/// that have been instantiated via C++ template instantiation (called
+/// via InstantiateDecl).
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl,
+                                    bool &Redeclaration,
+                                    bool &OverloadableAttrRequired) {
+  bool InvalidDecl = false;
+
+  // Semantic checking for this function declaration (in isolation).
+  if (getLangOptions().CPlusPlus) {
+    // C++-specific checks.
+    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
+      InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
+    else if (isa<CXXDestructorDecl>(NewFD)) {
+      CXXRecordDecl *Record = cast<CXXRecordDecl>(NewFD->getParent());
+      Record->setUserDeclaredDestructor(true);
+      // C++ [class]p4: A POD-struct is an aggregate class that has [...] no
+      // user-defined destructor.
+      Record->setPOD(false);
+    } else if (CXXConversionDecl *Conversion 
+               = dyn_cast<CXXConversionDecl>(NewFD))
+      ActOnConversionDeclarator(Conversion);
+    
+    // Extra checking for C++ overloaded operators (C++ [over.oper]).
+    if (NewFD->isOverloadedOperator() &&
+        CheckOverloadedOperatorDeclaration(NewFD))
+      InvalidDecl = true;
+  }
+
+  // Check for a previous declaration of this name.
   if (!PrevDecl && NewFD->isExternC(Context)) {
     // Since we did not find anything by this name and we're declaring
     // an extern "C" function, look for a non-visible extern "C"
     // declaration with the same name.
     llvm::DenseMap<DeclarationName, NamedDecl *>::iterator Pos
-      = LocallyScopedExternalDecls.find(Name);
+      = LocallyScopedExternalDecls.find(NewFD->getDeclName());
     if (Pos != LocallyScopedExternalDecls.end())
       PrevDecl = Pos->second;
   }
 
   // Merge or overload the declaration with an existing declaration of
   // the same name, if appropriate.
-  bool OverloadableAttrRequired = false;
   if (PrevDecl) {
     // Determine whether NewFD is an overload of PrevDecl or
     // a declaration that requires merging. If it's an overload,
@@ -2086,15 +2180,16 @@
 
       // Functions marked "overloadable" must have a prototype (that
       // we can't get through declaration merging).
-      if (!R->getAsFunctionProtoType()) {
+      if (!NewFD->getType()->getAsFunctionProtoType()) {
         Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype)
           << NewFD;
         InvalidDecl = true;
         Redeclaration = true;
 
         // Turn this into a variadic function with no parameters.
-        R = Context.getFunctionType(R->getAsFunctionType()->getResultType(),
-                                    0, 0, true, 0);
+        QualType R = Context.getFunctionType(
+                       NewFD->getType()->getAsFunctionType()->getResultType(),
+                       0, 0, true, 0);
         NewFD->setType(R);
       }
     }
@@ -2110,99 +2205,24 @@
       if (isa<OverloadedFunctionDecl>(PrevDecl))
         OldDecl = *MatchedDecl;
 
-      // NewFD and PrevDecl represent declarations that need to be
+      // NewFD and OldDecl represent declarations that need to be
       // merged. 
       if (MergeFunctionDecl(NewFD, OldDecl))
         InvalidDecl = true;
 
-      if (!InvalidDecl) {
+      if (!InvalidDecl)
         NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
-
-        // An out-of-line member function declaration must also be a
-        // definition (C++ [dcl.meaning]p1).
-        if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() &&
-            !InvalidDecl) {
-          Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
-            << D.getCXXScopeSpec().getRange();
-          NewFD->setInvalidDecl();
-        }
-      }
-    }
-  }
-
-  if (D.getCXXScopeSpec().isSet() &&
-      (!PrevDecl || !Redeclaration)) {
-    // The user tried to provide an out-of-line definition for a
-    // function that is a member of a class or namespace, but there
-    // was no such member function declared (C++ [class.mfct]p2, 
-    // C++ [namespace.memdef]p2). For example:
-    // 
-    // class X {
-    //   void f() const;
-    // }; 
-    //
-    // void X::f() { } // ill-formed
-    //
-    // Complain about this problem, and attempt to suggest close
-    // matches (e.g., those that differ only in cv-qualifiers and
-    // whether the parameter types are references).
-    Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
-      << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
-    InvalidDecl = true;
-    
-    LookupResult Prev = LookupQualifiedName(DC, Name, LookupOrdinaryName, 
-                                            true);
-    assert(!Prev.isAmbiguous() && 
-           "Cannot have an ambiguity in previous-declaration lookup");
-    for (LookupResult::iterator Func = Prev.begin(), FuncEnd = Prev.end();
-         Func != FuncEnd; ++Func) {
-      if (isa<FunctionDecl>(*Func) &&
-          isNearlyMatchingFunction(Context, cast<FunctionDecl>(*Func), NewFD))
-        Diag((*Func)->getLocation(), diag::note_member_def_close_match);
     }
-    
-    PrevDecl = 0;
   }
 
-  // Handle attributes. We need to have merged decls when handling attributes
-  // (for example to check for conflicts, etc).
-  ProcessDeclAttributes(NewFD, D);
-  AddKnownFunctionAttributes(NewFD);
-
-  if (OverloadableAttrRequired && !NewFD->getAttr<OverloadableAttr>()) {
-    // If a function name is overloadable in C, then every function
-    // with that name must be marked "overloadable".
-    Diag(NewFD->getLocation(), diag::err_attribute_overloadable_missing)
-      << Redeclaration << NewFD;
-    if (PrevDecl)
-      Diag(PrevDecl->getLocation(), 
-           diag::note_attribute_overloadable_prev_overload);
-    NewFD->addAttr(::new (Context) OverloadableAttr());
-  }
-
-  if (getLangOptions().CPlusPlus) {
+  if (getLangOptions().CPlusPlus && !CurContext->isRecord()) {
     // In C++, check default arguments now that we have merged decls. Unless
     // the lexical context is the class, because in this case this is done
     // during delayed parsing anyway.
-    if (!CurContext->isRecord())
-      CheckCXXDefaultArguments(NewFD);
-
-    // An out-of-line member function declaration must also be a
-    // definition (C++ [dcl.meaning]p1).
-    if (!IsFunctionDefinition && D.getCXXScopeSpec().isSet() && !InvalidDecl) {
-      Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
-        << D.getCXXScopeSpec().getRange();
-      InvalidDecl = true;
-    }
+    CheckCXXDefaultArguments(NewFD);
   }
 
-  // If this is a locally-scoped extern C function, update the
-  // map of such names.
-  if (CurContext->isFunctionOrMethod() && NewFD->isExternC(Context)
-      && !InvalidDecl)
-    RegisterLocallyScopedExternCDecl(NewFD, PrevDecl, S);
-
-  return NewFD;
+  return InvalidDecl || NewFD->isInvalidDecl();
 }
 
 bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) {
@@ -2588,40 +2608,24 @@
     }
   }
 
-  // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
-  // Doing the promotion here has a win and a loss. The win is the type for
-  // both Decl's and DeclRefExpr's will match (a convenient invariant for the
-  // code generator). The loss is the orginal type isn't preserved. For example:
-  //
-  // void func(int parmvardecl[5]) { // convert "int [5]" to "int *"
-  //    int blockvardecl[5];
-  //    sizeof(parmvardecl);  // size == 4
-  //    sizeof(blockvardecl); // size == 20
-  // }
-  //
-  // For expressions, all implicit conversions are captured using the
-  // ImplicitCastExpr AST node (we have no such mechanism for Decl's).
-  //
-  // FIXME: If a source translation tool needs to see the original type, then
-  // we need to consider storing both types (in ParmVarDecl)...
-  // 
-  
   // Parameters can not be abstract class types.
   if (RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType, 
                              diag::err_abstract_type_in_decl,
                              1 /* parameter type */)) 
     D.setInvalidType(true);
+
+  QualType T = adjustParameterType(parmDeclType);
   
-  if (parmDeclType->isArrayType()) {
-    // int x[restrict 4] ->  int *restrict
-    parmDeclType = Context.getArrayDecayedType(parmDeclType);
-  } else if (parmDeclType->isFunctionType())
-    parmDeclType = Context.getPointerType(parmDeclType);
-
-  ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, 
-                                         D.getIdentifierLoc(), II,
-                                         parmDeclType, StorageClass, 
-                                         0);
+  ParmVarDecl *New;
+  if (T == parmDeclType) // parameter type did not need adjustment
+    New = ParmVarDecl::Create(Context, CurContext, 
+                              D.getIdentifierLoc(), II,
+                              parmDeclType, StorageClass, 
+                              0);
+  else // keep track of both the adjusted and unadjusted types
+    New = OriginalParmVarDecl::Create(Context, CurContext, 
+                                      D.getIdentifierLoc(), II, T,
+                                      parmDeclType, StorageClass, 0);
   
   if (D.getInvalidType())
     New->setInvalidDecl();
@@ -2634,7 +2638,7 @@
   }
   // Parameter declarators cannot be interface types. All ObjC objects are
   // passed by reference.
-  if (parmDeclType->isObjCInterfaceType()) {
+  if (T->isObjCInterfaceType()) {
     Diag(D.getIdentifierLoc(), diag::err_object_cannot_be_by_value) 
          << "passed";
     New->setInvalidDecl();

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Mar 23 18:06:20 2009
@@ -43,6 +43,9 @@
     Decl *VisitFieldDecl(FieldDecl *D);
     Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
     Decl *VisitEnumDecl(EnumDecl *D);
+    Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
+    Decl *VisitParmVarDecl(ParmVarDecl *D);
+    Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D);
 
     // Base case. FIXME: Remove once we can instantiate everything.
     Decl *VisitDecl(Decl *) { 
@@ -192,6 +195,121 @@
   return Enum;
 }
 
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+  // Only handle actual methods; we'll deal with constructors,
+  // destructors, etc. separately.
+  if (D->getKind() != Decl::CXXMethod)
+    return 0;
+
+  QualType T = SemaRef.InstantiateType(D->getType(), TemplateArgs,
+                                       NumTemplateArgs, D->getLocation(),
+                                       D->getDeclName());
+  if (T.isNull())
+    return 0;
+
+  // Build the instantiated method declaration.
+  CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
+  CXXMethodDecl *Method
+    = CXXMethodDecl::Create(SemaRef.Context, Record, D->getLocation(), 
+                            D->getDeclName(), T, D->isStatic(), 
+                            D->isInline());
+  Method->setAccess(D->getAccess());
+  // FIXME: Duplicates some logic in ActOnFunctionDeclarator.
+  if (D->isVirtual()) {
+    Method->setVirtual();
+    Record->setAggregate(false);
+    Record->setPOD(false);
+    Record->setPolymorphic(true);
+  }
+  if (D->isDeleted())
+    Method->setDeleted();
+  if (D->isPure()) {
+    Method->setPure();
+    Record->setAbstract(true);
+  }
+  // FIXME: attributes
+  // FIXME: Method needs a pointer referencing where it came from.
+
+  // Instantiate the function parameters
+  {
+    TemplateDeclInstantiator ParamInstantiator(SemaRef, Method,
+                                               TemplateArgs, NumTemplateArgs);
+    llvm::SmallVector<ParmVarDecl *, 16> Params;
+    for (FunctionDecl::param_iterator P = Method->param_begin(), 
+                                   PEnd = Method->param_end();
+         P != PEnd; ++P) {
+      if (ParmVarDecl *PInst = (ParmVarDecl *)ParamInstantiator.Visit(*P))
+        Params.push_back(PInst);
+      else 
+        Method->setInvalidDecl();
+    }
+  }
+
+  NamedDecl *PrevDecl 
+    = SemaRef.LookupQualifiedName(Owner, Method->getDeclName(), 
+                                  Sema::LookupOrdinaryName, true);
+  // In C++, the previous declaration we find might be a tag type
+  // (class or enum). In this case, the new declaration will hide the
+  // tag type. Note that this does does not apply if we're declaring a
+  // typedef (C++ [dcl.typedef]p4).
+  if (PrevDecl && PrevDecl->getIdentifierNamespace() == Decl::IDNS_Tag)
+    PrevDecl = 0;
+  bool Redeclaration = false;
+  bool OverloadableAttrRequired = false;
+  if (SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration,
+                                       /*FIXME:*/OverloadableAttrRequired))
+    Method->setInvalidDecl();
+
+  if (!Method->isInvalidDecl() || !PrevDecl)
+    Owner->addDecl(Method);
+  return Method;
+}
+
+Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
+  QualType OrigT = SemaRef.InstantiateType(D->getOriginalType(), TemplateArgs,
+                                           NumTemplateArgs, D->getLocation(),
+                                           D->getDeclName());
+  if (OrigT.isNull())
+    return 0;
+
+  QualType T = SemaRef.adjustParameterType(OrigT);
+
+  if (D->getDefaultArg()) {
+    // FIXME: Leave a marker for "uninstantiated" default
+    // arguments. They only get instantiated on demand at the call
+    // site.
+    unsigned DiagID = SemaRef.Diags.getCustomDiagID(Diagnostic::Warning,
+        "sorry, dropping default argument during template instantiation");
+    SemaRef.Diag(D->getDefaultArg()->getSourceRange().getBegin(), DiagID)
+      << D->getDefaultArg()->getSourceRange();
+  }
+
+  // Allocate the parameter
+  ParmVarDecl *Param = 0;
+  if (T == OrigT)
+    Param = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+                                D->getIdentifier(), T, D->getStorageClass(), 
+                                0);
+  else
+    Param = OriginalParmVarDecl::Create(SemaRef.Context, Owner, 
+                                        D->getLocation(), D->getIdentifier(),
+                                        T, OrigT, D->getStorageClass(), 0);
+
+  // 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.
+  return Param;
+}
+
+Decl *
+TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) {
+  // Since parameter types can decay either before or after
+  // instantiation, we simply treat OriginalParmVarDecls as
+  // ParmVarDecls the same way, and create one or the other depending
+  // on what happens after template instantiation.
+  return VisitParmVarDecl(D);
+}
+
 Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner,
                             const TemplateArgument *TemplateArgs,
                             unsigned NumTemplateArgs) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Mar 23 18:06:20 2009
@@ -19,6 +19,30 @@
 #include "clang/Parse/DeclSpec.h"
 using namespace clang;
 
+/// \brief Perform adjustment on the parameter type of a function.
+///
+/// This routine adjusts the given parameter type @p T to the actual
+/// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], 
+/// C++ [dcl.fct]p3). The adjusted parameter type is returned. 
+QualType Sema::adjustParameterType(QualType T) {
+  // C99 6.7.5.3p7:
+  if (T->isArrayType()) {
+    // C99 6.7.5.3p7:
+    //   A declaration of a parameter as "array of type" shall be
+    //   adjusted to "qualified pointer to type", where the type
+    //   qualifiers (if any) are those specified within the [ and ] of
+    //   the array type derivation.
+    return Context.getArrayDecayedType(T);
+  } else if (T->isFunctionType())
+    // C99 6.7.5.3p8:
+    //   A declaration of a parameter as "function returning type"
+    //   shall be adjusted to "pointer to function returning type", as
+    //   in 6.3.2.1.
+    return Context.getPointerType(T);
+
+  return T;
+}
+
 /// \brief Convert the specified declspec to the appropriate type
 /// object.
 /// \param DS  the declaration specifiers
@@ -523,12 +547,8 @@
   
   bool Invalid = false;
   for (unsigned Idx = 0; Idx < NumParamTypes; ++Idx) {
-    QualType ParamType = ParamTypes[Idx];
-    if (ParamType->isArrayType())
-      ParamType = Context.getArrayDecayedType(ParamType);
-    else if (ParamType->isFunctionType())
-      ParamType = Context.getPointerType(ParamType);
-    else if (ParamType->isVoidType()) {
+    QualType ParamType = adjustParameterType(ParamTypes[Idx]);
+    if (ParamType->isVoidType()) {
       Diag(Loc, diag::err_param_with_void_type);
       Invalid = true;
     }
@@ -683,29 +703,14 @@
           ParmVarDecl *Param = (ParmVarDecl *)FTI.ArgInfo[i].Param;
           QualType ArgTy = Param->getType();
           assert(!ArgTy.isNull() && "Couldn't parse type?");
-          //
-          // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
-          // This matches the conversion that is done in 
-          // Sema::ActOnParamDeclarator(). Without this conversion, the
-          // argument type in the function prototype *will not* match the
-          // type in ParmVarDecl (which makes the code generator unhappy).
-          //
-          // FIXME: We still apparently need the conversion in 
-          // Sema::ActOnParamDeclarator(). This doesn't make any sense, since
-          // it should be driving off the type being created here.
-          // 
-          // FIXME: If a source translation tool needs to see the original type,
-          // then we need to consider storing both types somewhere...
-          // 
-          if (ArgTy->isArrayType()) {
-            ArgTy = Context.getArrayDecayedType(ArgTy);
-          } else if (ArgTy->isFunctionType())
-            ArgTy = Context.getPointerType(ArgTy);
-          
+
+          // Adjust the parameter type.
+          ArgTy = adjustParameterType(ArgTy);
+
           // Look for 'void'.  void is allowed only as a single argument to a
           // function with no other parameters (C99 6.7.5.3p10).  We record
           // int(void) as a FunctionProtoType with an empty argument list.
-          else if (ArgTy->isVoidType()) {
+          if (ArgTy->isVoidType()) {
             // If this is something like 'float(int, void)', reject it.  'void'
             // is an incomplete type (C99 6.2.5p19) and function decls cannot
             // have arguments of incomplete type.

Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=67575&r1=67574&r2=67575&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Mar 23 18:06:20 2009
@@ -101,8 +101,7 @@
 
 int A2::RC::x; // expected-error{{non-static data member defined out-of-line}}
 
-void A2::CC::NC::m(); // expected-error{{out-of-line declaration of a member must be a definition}} \
-     //  expected-error{{out-of-line declaration of a member must be a definition}}
+void A2::CC::NC::m(); // expected-error{{out-of-line declaration of a member must be a definition}}
 
 
 namespace E {

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

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-method.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-method.cpp Mon Mar 23 18:06:20 2009
@@ -0,0 +1,43 @@
+// RUN: clang -fsyntax-only -verify %s
+
+template<typename T>
+class X {
+public:
+  void f(T); // expected-error{{argument may not have 'void' type}}
+             // FIXME: source location isn't very good, because we're
+             // instantiating the type. Could we do better?
+  void g(T*);
+
+  static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
+};
+
+int identity(int x) { return x; }
+
+void test(X<int> *xi, int *ip, X<int(int)> *xf) {
+  xi->f(17);
+  xi->g(ip);
+  xf->f(&identity);
+  xf->g(identity);
+  X<int>::h(17, 25);
+  X<int(int)>::h(identity, &identity);
+}
+
+void test_bad() {
+  X<void> xv; // expected-note{{in instantiation of template class 'class X<void>' requested here}}
+}
+
+template<typename T, typename U>
+class Overloading {
+public:
+  int& f(T, T); // expected-note{{previous declaration is here}}
+  float& f(T, U); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+};
+
+void test_ovl(Overloading<int, long> *oil, int i, long l) {
+  int &ir = oil->f(i, i);
+  float &fr = oil->f(i, l);
+}
+
+void test_ovl_bad() {
+  Overloading<float, float> off; // expected-note{{in instantiation of template class 'class Overloading<float, float>' requested here}}
+}





More information about the cfe-commits mailing list