]> granicus.if.org Git - clang/commitdiff
Add support for C++ default arguments, and rework Parse-Sema
authorChris Lattner <sabre@nondot.org>
Tue, 8 Apr 2008 04:40:51 +0000 (04:40 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 8 Apr 2008 04:40:51 +0000 (04:40 +0000)
interaction for function parameters, fixing PR2046.

Patch by Doug Gregor!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49369 91177308-0d34-0410-b5e6-96231b3b80d8

30 files changed:
Driver/clang.cpp
include/clang/AST/Decl.h
include/clang/AST/ExprCXX.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/Action.h
include/clang/Parse/DeclSpec.h
lib/AST/Decl.cpp
lib/AST/DeclSerialization.cpp
lib/AST/Expr.cpp
lib/AST/ExprCXX.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtSerialization.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprConstant.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/Parser.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclObjC.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaType.cpp
test/CodeGen/cxx-default-arg.cpp [new file with mode: 0644]
test/Sema/arg-scope-c99.c [new file with mode: 0644]
test/Sema/arg-scope.c [new file with mode: 0644]
test/Sema/default1.c [new file with mode: 0644]
test/Sema/default1.cpp [new file with mode: 0644]
test/Sema/default2.cpp [new file with mode: 0644]

index 397c27db54b6b62e877abd45d2477272a78ec18d..6c82f195722fde0c68278611a26582053fe4cee8 100644 (file)
@@ -901,6 +901,11 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
               false, Headers);
       AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false,
               Headers);
+
+      // Fedora 8
+      AddPath("/usr/include/c++/4.1.2", System, true, false, false, Headers);
+      AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false, false, Headers);
+      AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false, Headers);
     }
     
     AddPath("/usr/local/include", System, false, false, false, Headers);
@@ -926,6 +931,10 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
     AddPath("/usr/lib/gcc/i486-linux-gnu/4.1.3/include", System,
             false, false, false, Headers);
 
+    // Fedora 8
+    AddPath("/usr/lib/gcc/i386-redhat-linux/4.1.2/include", System,
+            false, false, false, Headers);
+
     //Debian testing/lenny x86
     AddPath("/usr/lib/gcc/i486-linux-gnu/4.2.3/include", System,
             false, false, false, Headers);
index 3bae5e2d4c273f0231d226f58997b8d065d8c576..bce65f9b57d66960a0152955456b98d07dfe0b81 100644 (file)
@@ -246,15 +246,20 @@ class ParmVarDecl : public VarDecl {
   /// in, inout, etc.
   unsigned objcDeclQualifier : 6;
   
+  /// Default argument, if any.  [C++ Only]
+  Expr *DefaultArg;
+
   ParmVarDecl(DeclContext *CD, SourceLocation L,
               IdentifierInfo *Id, QualType T, StorageClass S,
-              ScopedDecl *PrevDecl)
+              Expr *DefArg, ScopedDecl *PrevDecl)
     : VarDecl(ParmVar, CD, L, Id, T, S, PrevDecl), 
-    objcDeclQualifier(OBJC_TQ_None) {}
+      objcDeclQualifier(OBJC_TQ_None), DefaultArg(DefArg) {}
+
 public:
   static ParmVarDecl *Create(ASTContext &C, DeclContext *CD,
                              SourceLocation L,IdentifierInfo *Id,
-                             QualType T, StorageClass S, ScopedDecl *PrevDecl);
+                             QualType T, StorageClass S, Expr *DefArg,
+                             ScopedDecl *PrevDecl);
   
   ObjCDeclQualifier getObjCDeclQualifier() const {
     return ObjCDeclQualifier(objcDeclQualifier);
@@ -262,6 +267,10 @@ public:
   void setObjCDeclQualifier(ObjCDeclQualifier QTVal) 
   { objcDeclQualifier = QTVal; }
     
+  const Expr *getDefaultArg() const { return DefaultArg; }
+  Expr *getDefaultArg() { return DefaultArg; }
+  void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
+
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return D->getKind() == ParmVar; }
   static bool classof(const ParmVarDecl *D) { return true; }
index 357fb9538f2cc128b0cbdcd240b0538bebec189e..3c99321a8a43fdb2d3679e08d99aca45933c70ae 100644 (file)
@@ -127,6 +127,45 @@ namespace clang {
     virtual child_iterator child_end();
   };
 
+  /// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a
+  /// function call argument that was created from the corresponding
+  /// parameter's default argument, when the call did not explicitly
+  /// supply arguments for all of the parameters.
+  class CXXDefaultArgExpr : public Expr {
+    ParmVarDecl *Param;
+  public:
+    // Param is the parameter whose default argument is used by this
+    // expression.
+    explicit CXXDefaultArgExpr(ParmVarDecl *param) 
+      : Expr(CXXDefaultArgExprClass, param->getDefaultArg()->getType()),
+        Param(param) { }
+
+    // Retrieve the parameter that the argument was created from.
+    const ParmVarDecl *getParam() const { return Param; }
+    ParmVarDecl *getParam() { return Param; }
+
+    // Retrieve the actual argument to the function call.
+    const Expr *getExpr() const { return Param->getDefaultArg(); }
+    Expr *getExpr() { return Param->getDefaultArg(); }
+
+    virtual SourceRange getSourceRange() const {
+      return Param->getDefaultArg()->getSourceRange();
+    }
+
+    static bool classof(const Stmt *T) {
+      return T->getStmtClass() == CXXDefaultArgExprClass;
+    }
+    static bool classof(const CXXDefaultArgExpr *) { return true; }
+
+    // Iterators
+    virtual child_iterator child_begin();
+    virtual child_iterator child_end();
+
+    // Serialization
+    virtual void EmitImpl(llvm::Serializer& S) const;
+    static CXXDefaultArgExpr* CreateImpl(llvm::Deserializer& D,
+                                         ASTContext& C);
+  };
 }  // end namespace clang
 
 #endif
index 4c0fd7a242d23e72ca5a0b8415f706b0e9c97b13..e3f0273308ab91981919d3ded0362b2a8100083f 100644 (file)
@@ -91,6 +91,7 @@ STMT(58, ChooseExpr           , Expr)
 STMT(60, CXXCastExpr          , Expr)
 STMT(61, CXXBoolLiteralExpr   , Expr)
 STMT(62, CXXThrowExpr         , Expr)
+STMT(63, CXXDefaultArgExpr    , Expr)
 
 // Obj-C Expressions.
 STMT(70, ObjCStringLiteral    , Expr)
index 1de1b6b80f5206de3465a294bef3385c5e8f5086..611edf51f58c1b5d35ce463f0a1d99b7c1cba6fb 100644 (file)
@@ -243,7 +243,6 @@ DIAG(err_pp_I_dash_not_supported, ERROR,
 //===----------------------------------------------------------------------===//
 // Parser Diagnostics
 //===----------------------------------------------------------------------===//
-
 DIAG(w_type_defaults_to_int, WARNING,
      "type defaults to 'int'")
 DIAG(w_no_declarators, WARNING,
@@ -314,7 +313,7 @@ DIAG(ext_gnu_old_style_field_designator, EXTENSION,
      "use of GNU old-style field designator extension")
 DIAG(ext_gnu_case_range, EXTENSION,
      "use of GNU case range extension")
-     
+   
 // Generic errors.
 DIAG(err_parse_error, ERROR,
      "parse error")
@@ -621,7 +620,14 @@ DIAG(err_no_matching_param, ERROR,
      "parameter named '%0' is missing")
 DIAG(ext_param_not_declared, EXTENSION,
      "parameter '%0' was not declared, defaulting to type 'int'")
-
+DIAG(err_param_default_argument, ERROR,
+     "C does not support default arguments")
+DIAG(err_param_default_argument_redefinition, ERROR,
+     "redefinition of default argument")
+DIAG(err_param_default_argument_missing, ERROR,
+     "missing default argument on parameter")
+DIAG(err_param_default_argument_missing_name, ERROR,
+     "missing default argument on parameter '%0'")
 DIAG(err_previous_definition, ERROR,
      "previous definition is here")
 DIAG(err_previous_use, ERROR,
index 83d1fea715913f68550a0e9ab5b143f32b10e9e9..fb180c2d1a84e8faed94feb080c85a16237799b0 100644 (file)
@@ -107,6 +107,14 @@ public:
     return 0;
   }
 
+  /// ActOnParamDeclarator - This callback is invoked when a parameter
+  /// declarator is parsed. This callback only occurs for functions
+  /// with prototypes. S is the function prototype scope for the
+  /// parameters (C++ [basic.scope.proto]).
+  virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D) {
+    return 0;
+  }
+
   /// AddInitializerToDecl - This action is called immediately after 
   /// ParseDeclarator (when an initializer is present). The code is factored 
   /// this way to make sure we are able to handle the following:
@@ -173,10 +181,6 @@ public:
     return 0;
   }
   
-  virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D) {
-    return 0;
-  }
-  
   enum TagKind {
     TK_Reference,   // Reference to a tag:  'struct foo *X;'
     TK_Declaration, // Fwd decl of a tag:   'struct foo;'
@@ -503,6 +507,13 @@ public:
                                 SourceLocation RPLoc) {
     return 0;
   }
+
+  //===------------------------- C++ Declarations -------------------------===//
+  /// ActOnParamDefaultArgument - Parse default argument for function parameter
+  virtual void ActOnParamDefaultArgument(DeclTy *param,
+                                         SourceLocation EqualLoc,
+                                         ExprTy *defarg) {
+  }
   
   //===------------------------- C++ Expressions --------------------------===//
   
index e52f307e6e369057d30f5724a91a592c8f1af949..6204a383b9a3e4c5660ba52f6442e29ca4d82103 100644 (file)
@@ -416,14 +416,10 @@ struct DeclaratorChunk {
   struct ParamInfo {
     IdentifierInfo *Ident;
     SourceLocation IdentLoc;
-    Action::TypeTy *TypeInfo;
-    bool InvalidType;
-    AttributeList *AttrList;
+    Action::DeclTy *Param;
     ParamInfo() {}
-    ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::TypeTy *typ,
-              bool flag = false, AttributeList *AL = 0)
-      : Ident(ident), IdentLoc(iloc), TypeInfo(typ), InvalidType(flag),
-        AttrList(AL) {}
+    ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param)
+      : Ident(ident), IdentLoc(iloc), Param(param) {}
   };
   
   struct FunctionTypeInfo {
index e27015b7efd815f3addd8311a3954bf415e9b06d..8228eceebf6dc401ba6cdf9b73d519ae79cb5ede 100644 (file)
@@ -224,9 +224,9 @@ FileVarDecl *FileVarDecl::Create(ASTContext &C, DeclContext *CD,
 ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *CD,
                                  SourceLocation L, IdentifierInfo *Id,
                                  QualType T, StorageClass S,
-                                 ScopedDecl *PrevDecl) {
+                                 Expr *DefArg, ScopedDecl *PrevDecl) {
   void *Mem = C.getAllocator().Allocate<ParmVarDecl>();
-  return new (Mem) ParmVarDecl(CD, L, Id, T, S, PrevDecl);
+  return new (Mem) ParmVarDecl(CD, L, Id, T, S, DefArg, PrevDecl);
 }
 
 FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *CD,
index bc5310c4142f60d8b880ca6212f1b3a136b7484a..14666d6f00206f9ca3654c0014a3a8ed04b729b8 100644 (file)
@@ -226,15 +226,16 @@ FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D, ASTContext& C) {
 void ParmVarDecl::EmitImpl(llvm::Serializer& S) const {
   VarDecl::EmitImpl(S);
   S.EmitInt(getObjCDeclQualifier());        // From ParmVarDecl.
+  S.EmitOwnedPtr(getDefaultArg());          // From ParmVarDecl.
 }
 
 ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D, ASTContext& C) {
   ParmVarDecl* decl =
-    new ParmVarDecl(0, SourceLocation(),NULL,QualType(),None,NULL);
+    new ParmVarDecl(0, SourceLocation(), NULL, QualType(), None, NULL, NULL);
   
   decl->VarDecl::ReadImpl(D, C);
   decl->objcDeclQualifier = static_cast<ObjCDeclQualifier>(D.ReadInt());
-
+  decl->DefaultArg = D.ReadOwnedPtr<Expr>(C);
   return decl;
 }
 
index 5205702f29730c74362a1f2d00a303e784b602c2..0287aa0831952c5906e248ce49c75e0644b86443 100644 (file)
@@ -337,6 +337,9 @@ bool Expr::hasLocalSideEffect() const {
     if (getType()->isVoidType())
       return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect();
     return false;
+
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)->getExpr()->hasLocalSideEffect();
   }     
 }
 
@@ -401,6 +404,8 @@ Expr::isLvalueResult Expr::isLvalue() const {
     return LV_Valid;
   case PreDefinedExprClass:
     return LV_Valid;
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue();
   default:
     break;
   }
@@ -465,6 +470,8 @@ bool Expr::hasGlobalStorage() const {
     return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage();
   case PreDefinedExprClass:
     return true;
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage();
   }
 }
 
@@ -636,6 +643,8 @@ bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
     }
     return true;
   }
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)->getExpr()->isConstantExpr(Ctx, Loc);
   }
 }
 
@@ -981,6 +990,9 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
       return false;
     break;
   }
+  case CXXDefaultArgExprClass:
+    return cast<CXXDefaultArgExpr>(this)
+             ->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
   }
 
   // Cases that are valid constant exprs fall through to here.
@@ -1009,6 +1021,9 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx) const {
     // Accept ((void*)0) as a null pointer constant, as many other
     // implementations do.
     return PE->getSubExpr()->isNullPointerConstant(Ctx);
+  } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) {
+    // See through default argument expressions
+    return DefaultArg->getExpr()->isNullPointerConstant(Ctx);
   }
   
   // This expression must be an integer type.
index 3bc32e75d87e3cb9c86952850b68bed69c112a50..03faf8b8b510c15195763e327a006271b0812fc1 100644 (file)
@@ -45,3 +45,11 @@ Stmt::child_iterator CXXThrowExpr::child_end() {
     return reinterpret_cast<Stmt**>(&Op)+0;
   return reinterpret_cast<Stmt**>(&Op)+1;
 }
+
+// CXXDefaultArgExpr
+Stmt::child_iterator CXXDefaultArgExpr::child_begin() {
+  return reinterpret_cast<Stmt**>(Param->getDefaultArg());
+}
+Stmt::child_iterator CXXDefaultArgExpr::child_end() {
+  return reinterpret_cast<Stmt**>(Param->getDefaultArg())+1;
+}
index ba82b7fcff760a0d4cab8bdcd85d562429181ff7..a76fd1f9b5e9f6daf697069eff6007b4e5ad455a 100644 (file)
@@ -658,6 +658,11 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
   PrintExpr(Call->getCallee());
   OS << "(";
   for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
+    if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
+      // Don't print any defaulted arguments
+      break;
+    }
+
     if (i) OS << ", ";
     PrintExpr(Call->getArg(i));
   }
@@ -789,6 +794,10 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
   }
 }
 
+void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
+  // Nothing to print: we picked up the default argument
+}
+
 // Obj-C 
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
index 41569df8f21881ef16362c69e1590c087e4a0aee..7058c0ce2f19c7944e0bb3ee2a776be8f1b3a6f0 100644 (file)
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "llvm/Bitcode/Serialize.h"
 #include "llvm/Bitcode/Deserialize.h"
 
@@ -185,6 +186,13 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
       
     case ObjCStringLiteralClass:
       return ObjCStringLiteral::CreateImpl(D, C);
+      
+    //==--------------------------------------==//
+    //    C++
+    //==--------------------------------------==//
+    case CXXDefaultArgExprClass:
+      return CXXDefaultArgExpr::CreateImpl(D, C);
+      
   }
 }
 
@@ -1002,3 +1010,16 @@ ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D, ASTContext& C)
   StringLiteral* String = cast<StringLiteral>(D.ReadOwnedPtr<Stmt>(C));
   return new ObjCStringLiteral(String,T,L);
 }
+
+//===----------------------------------------------------------------------===//
+//   C++ Serialization
+//===----------------------------------------------------------------------===//
+void CXXDefaultArgExpr::EmitImpl(Serializer& S) const {
+  S.EmitPtr(Param);
+}
+
+CXXDefaultArgExpr *CXXDefaultArgExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+  ParmVarDecl* Param = 0;
+  D.ReadPtr(Param, false);
+  return new CXXDefaultArgExpr(Param);
+}
index 3bfcc10f7fe32aee0631b19c2527ed3a3addcddc..b5c755a582f6f29c9775c8768d9abd5af528962f 100644 (file)
@@ -86,6 +86,9 @@ public:
   
   void VisitConditionalOperator(const ConditionalOperator *CO);
   void VisitInitListExpr(InitListExpr *E);
+  void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+    Visit(DAE->getExpr());
+  }
 
   void EmitInitializationToLValue(Expr *E, LValue Address);
   void EmitNullInitializationToLValue(LValue Address, QualType T);
index 1e8c8a37f2d65916ee20038dcebb448a5c46823d..a486d6ae15dc4ac6c47753129febb36abe6819d0 100644 (file)
@@ -120,6 +120,9 @@ public:
   ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
     return Visit(E->getSubExpr());
   }
+  ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+    return Visit(DAE->getExpr());
+  }
   
   struct BinOpInfo {
     ComplexPairTy LHS;
index e2405b88f37ec4806cdb512681ec6eba6310d80f..2ca71c31531e6f6bda1cd9c7225bb97aba63f61c 100644 (file)
@@ -69,6 +69,10 @@ public:
     return EmitConversion(C, E->getSubExpr()->getType(), E->getType());    
   }
 
+  llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+    return Visit(DAE->getExpr());
+  }
+
   llvm::Constant *EmitArrayInitialization(InitListExpr *ILE,
                                           const llvm::ArrayType *AType) {
     std::vector<llvm::Constant*> Elts;
index 89779075a4a0a182a5d170be6475bb4ad231345f..2f03f88ebf2e92e069b98634609523c8704288d5 100644 (file)
@@ -169,7 +169,7 @@ public:
   Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
     return Visit(E->getInitializer());
   }
-
+  
   Value *VisitImplicitCastExpr(const ImplicitCastExpr *E);
   Value *VisitCastExpr(const CastExpr *E) { 
     return EmitCastExpr(E->getSubExpr(), E->getType());
@@ -220,6 +220,9 @@ public:
     return Visit(E->getSubExpr());
   }
   Value *VisitUnaryOffsetOf(const UnaryOperator *E);
+  Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+    return Visit(DAE->getExpr());
+  }
     
   // Binary Operators.
   Value *EmitMul(const BinOpInfo &Ops) {
index 0eb5c1f2576a4c41ad2cf9c6c4de087546447e15..0eb95fa908c25a89d01bc7810a189ed2f4156ceb 100644 (file)
@@ -1232,8 +1232,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
 ///
 ///       parameter-declaration: [C99 6.7.5]
 ///         declaration-specifiers declarator
+/// [C++]   declaration-specifiers declarator '=' assignment-expression
 /// [GNU]   declaration-specifiers declarator attributes
 ///         declaration-specifiers abstract-declarator[opt] 
+/// [C++]   declaration-specifiers abstract-declarator[opt] '=' assignment-expression
 /// [GNU]   declaration-specifiers abstract-declarator[opt] attributes
 ///
 void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
@@ -1265,11 +1267,9 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
   
   // Build up an array of information about the parsed arguments.
   llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
-  llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
-  
-  // Enter function-declaration scope, limiting any declarators for struct
-  // tags to the function prototype scope.
-  // FIXME: is this needed?
+
+  // Enter function-declaration scope, limiting any declarators to the
+  // function prototype scope, including parameter declarators.
   EnterScope(Scope::DeclScope);
   
   bool IsVariadic = false;
@@ -1307,14 +1307,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
     // Remember this parsed parameter in ParamInfo.
     IdentifierInfo *ParmII = ParmDecl.getIdentifier();
     
-    // Verify that the argument identifier has not already been mentioned.
-    if (ParmII && !ParamsSoFar.insert(ParmII)) {
-      Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition,
-           ParmII->getName());
-      ParmII = 0;
-      ParmDecl.setInvalidType(true);
-    }
-
     // If no parameter was specified, verify that *something* was specified,
     // otherwise we have a missing type and identifier.
     if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && 
@@ -1327,12 +1319,37 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
       
       // Inform the actions module about the parameter declarator, so it gets
       // added to the current scope.
-      Action::TypeResult ParamTy =
-        Actions.ActOnParamDeclaratorType(CurScope, ParmDecl);
+      DeclTy *Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+
+      // Parse the default argument, if any. We parse the default
+      // arguments in all dialects; the semantic analysis in
+      // ActOnParamDefaultArgument will reject the default argument in
+      // C.
+      if (Tok.is(tok::equal)) {
+        SourceLocation EqualLoc = Tok.getLocation();
+        
+        // Consume the '='.
+        ConsumeToken();
+        
+        // Parse the default argument
+        // FIXME: For C++, name lookup from within the default argument 
+        // should be able to find parameter names, but we haven't put them
+        // in the scope. This means that we will accept ill-formed code
+        // such as:
+        //
+        //   int x;
+        //   void f(int x = x) { }
+        ExprResult DefArgResult = ParseAssignmentExpression();
+        if (DefArgResult.isInvalid) {
+          SkipUntil(tok::comma, tok::r_paren, true, true);
+        } else {
+          // Inform the actions module about the default argument
+          Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.Val);
+        }
+      }
       
       ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, 
-          ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(),
-          ParmDecl.getDeclSpec().TakeAttributes()));
+                             ParmDecl.getIdentifierLoc(), Param));
     }
 
     // If the next token is a comma, consume it and keep reading arguments.
@@ -1354,7 +1371,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
   MatchRHSPunctuation(tok::r_paren, LParenLoc);
 }
 
-
 /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
 /// we found a K&R-style identifier list instead of a type argument list.  The
 /// current token is known to be the first identifier in the list.
index cd99fc04ebe08fc4a216f20cdab7d14cf8ac5c99..7e41bcc92e339ee8feec481e713bd8b05e7531ef 100644 (file)
@@ -509,6 +509,10 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
   // We know that the top-level of this declarator is a function.
   DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
 
+  // Enter function-declaration scope, limiting any declarators to the
+  // function prototype scope, including parameter declarators.
+  EnterScope(Scope::DeclScope);
+
   // Read all the argument declarations.
   while (isDeclarationSpecifier()) {
     SourceLocation DSStart = Tok.getLocation();
@@ -555,10 +559,10 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
         AttrList = ParseAttributes();
       
       // Ask the actions module to compute the type for this declarator.
-      Action::TypeResult TR =
-        Actions.ActOnParamDeclaratorType(CurScope, ParmDeclarator);
+      Action::DeclTy *Param = 
+        Actions.ActOnParamDeclarator(CurScope, ParmDeclarator);
 
-      if (!TR.isInvalid && 
+      if (Param && 
           // A missing identifier has already been diagnosed.
           ParmDeclarator.getIdentifier()) {
 
@@ -575,12 +579,12 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
           
           if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
             // Reject redefinitions of parameters.
-            if (FTI.ArgInfo[i].TypeInfo) {
+            if (FTI.ArgInfo[i].Param) {
               Diag(ParmDeclarator.getIdentifierLoc(),
                    diag::err_param_redefinition,
                    ParmDeclarator.getIdentifier()->getName());
             } else {
-              FTI.ArgInfo[i].TypeInfo = TR.Val;
+              FTI.ArgInfo[i].Param = Param;
             }
             break;
           }
@@ -611,6 +615,9 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
     }
   }
   
+  // Leave prototype scope.
+  ExitScope();
+
   // The actions module must verify that all arguments were declared.
 }
 
index 70aaf24791604f7c76c0ecf8701b5769a37defb1..b2a88eb635f6bf7b14674c43612e0fbbeecdb421 100644 (file)
@@ -202,14 +202,16 @@ public:
 
   
   virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
-  
-  virtual TypeResult ActOnParamDeclaratorType(Scope *S, Declarator &D);
 private:
   //===--------------------------------------------------------------------===//
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
   //
   virtual DeclTy *isTypeName(const IdentifierInfo &II, Scope *S);
   virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
+  virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
+  virtual void ActOnParamDefaultArgument(DeclTy *param, 
+                                         SourceLocation EqualLoc,
+                                         ExprTy *defarg);
   void AddInitializerToDecl(DeclTy *dcl, ExprTy *init);
   virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
 
@@ -259,10 +261,15 @@ private:
   TypedefDecl *MergeTypeDefDecl(TypedefDecl *New, Decl *Old);
   FunctionDecl *MergeFunctionDecl(FunctionDecl *New, Decl *Old);
   VarDecl *MergeVarDecl(VarDecl *New, Decl *Old);
+  FunctionDecl *MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old);
+
+  /// Helpers for dealing with function parameters
+  bool CheckParmsForFunctionDef(FunctionDecl *FD);
+  ParmVarDecl *CreateImplicitParameter(Scope *S, IdentifierInfo *Id, 
+                                       SourceLocation IdLoc, QualType Type);
+  void CheckCXXDefaultArguments(FunctionDecl *FD);
 
   /// More parsing and symbol table subroutines...
-  ParmVarDecl *ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI, 
-                                    Scope *FnBodyScope);  
   Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
                    bool enableLazyBuiltinCreation = true);
   ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
index 0f464a0bc79f6ea4148b93cb787e9a3552c39f45..5451ec27c05386ce37b91d1f0908d9b12a331d6e 100644 (file)
@@ -263,9 +263,10 @@ static void MergeAttributes(Decl *New, Decl *Old) {
   }
 }
 
-/// MergeFunctionDecl - We just parsed a function 'New' which has the same name
-/// and scope as a previous declaration 'Old'.  Figure out how to resolve this
-/// situation, merging decls or emitting diagnostics as appropriate.
+/// MergeFunctionDecl - We just parsed a function 'New' from
+/// declarator D which has the same name and scope as a previous
+/// declaration 'Old'.  Figure out how to resolve this situation,
+/// merging decls or emitting diagnostics as appropriate.
 ///
 FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
   // Verify the old decl was also a function.
@@ -276,17 +277,24 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     Diag(OldD->getLocation(), diag::err_previous_definition);
     return New;
   }
-
+  
   MergeAttributes(New, Old);
 
-  
   QualType OldQType = Context.getCanonicalType(Old->getType());
   QualType NewQType = Context.getCanonicalType(New->getType());
   
-  // Function types need to be compatible, not identical. This handles
+  // C++ [dcl.fct]p3:
+  //   All declarations for a function shall agree exactly in both the
+  //   return type and the parameter-type-list.
+  if (getLangOptions().CPlusPlus && OldQType == NewQType)
+    return MergeCXXFunctionDecl(New, Old);
+
+  // C: Function types need to be compatible, not identical. This handles
   // duplicate function decls like "void f(int); void f(enum X);" properly.
-  if (Context.functionTypesAreCompatible(OldQType, NewQType))
+  if (!getLangOptions().CPlusPlus &&
+      Context.functionTypesAreCompatible(OldQType, NewQType)) {
     return New;
+  }
 
   // A function that has already been declared has been redeclared or defined
   // with a different type- show appropriate diagnostic
@@ -295,7 +303,7 @@ FunctionDecl *Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) {
     PrevDiag = diag::err_previous_definition;
   else if (Old->isImplicit())
     PrevDiag = diag::err_previous_implicit_declaration;
-  else
+  else 
     PrevDiag = diag::err_previous_declaration;
 
   // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
@@ -413,6 +421,49 @@ VarDecl *Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
   return New;
 }
 
+/// CheckParmsForFunctionDef - Check that the parameters of the given
+/// function are appropriate for the definition of a function. This
+/// takes care of any checks that cannot be performed on the
+/// declaration itself, e.g., that the types of each of the function
+/// parameters are complete.
+bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
+  bool HasInvalidParm = false;
+  for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+    ParmVarDecl *Param = FD->getParamDecl(p);
+
+    // C99 6.7.5.3p4: the parameters in a parameter type list in a
+    // function declarator that is part of a function definition of
+    // that function shall not have incomplete type.
+    if (Param->getType()->isIncompleteType() &&
+        !Param->isInvalidDecl()) {
+      Diag(Param->getLocation(), diag::err_typecheck_decl_incomplete_type,
+           Param->getType().getAsString());
+      Param->setInvalidDecl();
+      HasInvalidParm = true;
+    }
+  }
+
+  return HasInvalidParm;
+}
+
+/// CreateImplicitParameter - Creates an implicit function parameter
+/// in the scope S and with the given type. This routine is used, for
+/// example, to create the implicit "self" parameter in an Objective-C
+/// method.
+ParmVarDecl *
+Sema::CreateImplicitParameter(Scope *S, IdentifierInfo *Id, 
+                              SourceLocation IdLoc, QualType Type) {
+  ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, IdLoc, Id, Type, 
+                                         VarDecl::None, 0, 0);
+  if (Id) {
+    New->setNext(Id->getFETokenInfo<ScopedDecl>());
+    Id->setFETokenInfo(New);
+    S->AddDecl(New);
+  }
+
+  return New;
+}
+
 /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
 /// no declarator (e.g. "struct foo;") is parsed.
 Sema::DeclTy *Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
@@ -769,7 +820,38 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
     // Handle attributes.
     HandleDeclAttributes(NewFD, D.getDeclSpec().getAttributes(),
                          D.getAttributes());
-    
+
+    // Copy the parameter declarations from the declarator D to
+    // the function declaration NewFD, if they are available.
+    if (D.getNumTypeObjects() > 0 &&
+        D.getTypeObject(0).Fun.hasPrototype) {
+      DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+
+      // Create Decl objects for each parameter, adding them to the
+      // FunctionDecl.
+      llvm::SmallVector<ParmVarDecl*, 16> Params;
+  
+      // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs
+      // function that takes no arguments, not a function that takes a
+      // single void argument.  FIXME: Is this really the right place
+      // to check for this? C++ says that the parameter list (void) is
+      // the same as an empty parameter list, whereas the parameter
+      // list (T) (with T typedef'd to void) is not. For C++, this
+      // should be handled in the parser. Check C89 and C99 standards
+      // to see what the correct behavior is.
+      if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
+          FTI.ArgInfo[0].Param &&
+          !((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType().getCVRQualifiers() &&
+          ((ParmVarDecl*)FTI.ArgInfo[0].Param)->getType()->isVoidType()) {
+        // empty arg list, don't push any params.
+      } else {
+        for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i)
+          Params.push_back((ParmVarDecl *)FTI.ArgInfo[i].Param);
+      }
+  
+      NewFD->setParams(&Params[0], Params.size());
+    }
+
     // Merge the decl with the existing one if appropriate. Since C functions
     // are in a flat namespace, make sure we consider decls in outer scopes.
     if (PrevDecl) {
@@ -777,6 +859,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
       if (NewFD == 0) return 0;
     }
     New = NewFD;
+
+    // In C++, check default arguments now that we have merged decls.
+    if (getLangOptions().CPlusPlus)
+      CheckCXXDefaultArguments(NewFD);
   } else {
     if (R.getTypePtr()->isObjCInterfaceType()) {
       Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object,
@@ -982,20 +1068,47 @@ Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
   return NewGroup;
 }
 
-// Called from Sema::ParseStartOfFunctionDef().
-ParmVarDecl *
-Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI,
-                           Scope *FnScope) {
-  IdentifierInfo *II = PI.Ident;
+/// ActOnParamDeclarator - Called from Parser::ParseFunctionDeclarator()
+/// to introduce parameters into function prototype scope.
+Sema::DeclTy *
+Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
+  DeclSpec &DS = D.getDeclSpec();
+  
+  // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
+  if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
+      DS.getStorageClassSpec() != DeclSpec::SCS_register) {
+    Diag(DS.getStorageClassSpecLoc(),
+         diag::err_invalid_storage_class_in_func_decl);
+    DS.ClearStorageClassSpecs();
+  }
+  if (DS.isThreadSpecified()) {
+    Diag(DS.getThreadSpecLoc(),
+         diag::err_invalid_storage_class_in_func_decl);
+    DS.ClearStorageClassSpecs();
+  }
+  
+  
+  // In this context, we *do not* check D.getInvalidType(). If the declarator
+  // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
+  // though it will not reflect the user specified type.
+  QualType parmDeclType = GetTypeForDeclarator(D, S);
+  
+  assert(!parmDeclType.isNull() && "GetTypeForDeclarator() returned null type");
+
   // TODO: CHECK FOR CONFLICTS, multiple decls with same name in one scope.
   // Can this happen for params?  We already checked that they don't conflict
   // among each other.  Here they can only shadow globals, which is ok.
-  if (/*Decl *PrevDecl = */LookupDecl(II, Decl::IDNS_Ordinary, FnScope)) {
-    
+  IdentifierInfo *II = D.getIdentifier();
+  if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) {
+    if (S->isDeclScope(PrevDecl)) {
+      Diag(D.getIdentifierLoc(), diag::err_param_redefinition,
+           dyn_cast<NamedDecl>(PrevDecl)->getName());
+
+      // Recover by removing the name
+      II = 0;
+      D.SetIdentifier(0, D.getIdentifierLoc());
+    }
   }
-  
-  // FIXME: Handle storage class (auto, register). No declarator?
-  // TODO: Chain to previous parameter with the prevdeclarator chain?
 
   // 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
@@ -1014,29 +1127,29 @@ Sema::ActOnParamDeclarator(struct DeclaratorChunk::ParamInfo &PI,
   // FIXME: If a source translation tool needs to see the original type, then
   // we need to consider storing both types (in ParmVarDecl)...
   // 
-  QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo);
   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, PI.IdentLoc, II,
-                                         parmDeclType, 
-                                         VarDecl::None, 0);
+  ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, 
+                                         D.getIdentifierLoc(), II,
+                                         parmDeclType, VarDecl::None, 
+                                         0, 0);
   
-  if (PI.InvalidType)
+  if (D.getInvalidType())
     New->setInvalidDecl();
     
-  // If this has an identifier, add it to the scope stack.
   if (II) {
     New->setNext(II->getFETokenInfo<ScopedDecl>());
     II->setFETokenInfo(New);
-    FnScope->AddDecl(New);
+    S->AddDecl(New);
   }
 
-  HandleDeclAttributes(New, PI.AttrList, 0);
+  HandleDeclAttributes(New, D.getAttributes(), 0);
   return New;
+
 }
 
 Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
@@ -1044,17 +1157,23 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
   assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
          "Not a function declarator!");
   DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
-  
+
   // Verify 6.9.1p6: 'every identifier in the identifier list shall be declared'
   // for a K&R function.
   if (!FTI.hasPrototype) {
     for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
-      if (FTI.ArgInfo[i].TypeInfo == 0) {
+      if (FTI.ArgInfo[i].Param == 0) {
         Diag(FTI.ArgInfo[i].IdentLoc, diag::ext_param_not_declared,
              FTI.ArgInfo[i].Ident->getName());
         // Implicitly declare the argument as type 'int' for lack of a better
         // type.
-        FTI.ArgInfo[i].TypeInfo = Context.IntTy.getAsOpaquePtr();
+        DeclSpec DS;
+        const char* PrevSpec; // unused
+        DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, 
+                           PrevSpec);
+        Declarator ParamD(DS, Declarator::KNRTypeListContext);
+        ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc);
+        FTI.ArgInfo[i].Param = ActOnParamDeclarator(FnBodyScope, ParamD);
       }
     }
 
@@ -1063,8 +1182,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
     if (FTI.NumArgs)
       FTI.hasPrototype = true;
   } else {
-    // FIXME: Diagnose arguments without names in C.
-    
+    // FIXME: Diagnose arguments without names in C. 
   }
   
   Scope *GlobalScope = FnBodyScope->getParent();
@@ -1083,37 +1201,21 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) {
   FunctionDecl *FD = cast<FunctionDecl>(decl);
   CurFunctionDecl = FD;
   PushDeclContext(FD);
-  
-  // Create Decl objects for each parameter, adding them to the FunctionDecl.
-  llvm::SmallVector<ParmVarDecl*, 16> Params;
-  
-  // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs function that takes
-  // no arguments, not a function that takes a single void argument.
-  if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 &&
-      !QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo).getCVRQualifiers() &&
-      QualType::getFromOpaquePtr(FTI.ArgInfo[0].TypeInfo)->isVoidType()) {
-    // empty arg list, don't push any params.
-  } else {
-    for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
-      ParmVarDecl *parmDecl;
-      
-      parmDecl = ActOnParamDeclarator(D.getTypeObject(0).Fun.ArgInfo[i],
-                                      FnBodyScope);
-      // C99 6.7.5.3p4: the parameters in a parameter type list in a function
-      // declarator that is part of a function definition of that function
-      // shall not have incomplete type.
-      if (parmDecl->getType()->isIncompleteType() &&
-          !parmDecl->isInvalidDecl()) {
-        Diag(parmDecl->getLocation(), diag::err_typecheck_decl_incomplete_type,
-             parmDecl->getType().getAsString());
-        parmDecl->setInvalidDecl();
-      }
-      Params.push_back(parmDecl);
+    
+  // Check the validity of our function parameters
+  CheckParmsForFunctionDef(FD);
+
+  // Introduce our parameters into the function scope
+  for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+    ParmVarDecl *Param = FD->getParamDecl(p);
+    // If this has an identifier, add it to the scope stack.
+    if (IdentifierInfo *II = Param->getIdentifier()) {
+      Param->setNext(II->getFETokenInfo<ScopedDecl>());
+      II->setFETokenInfo(Param);
+      FnBodyScope->AddDecl(Param);
     }
   }
-  
-  FD->setParams(&Params[0], Params.size());
-  
+
   return FD;
 }
 
index c94c681fcb50f22619ca0005550f0c06123fdb81..a9efe6c251592674cc6608e04579dccbbd44715f 100644 (file)
@@ -42,32 +42,31 @@ void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) {
   // Insert the invisible arguments, self and _cmd!
   PI.Ident = &Context.Idents.get("self");
   PI.IdentLoc = SourceLocation(); // synthesized vars have a null location.
-  PI.InvalidType = false;
-  PI.AttrList = 0;
-  PI.TypeInfo = Context.getObjCIdType().getAsOpaquePtr();
-
+  QualType selfTy = Context.getObjCIdType();
   if (MDecl->isInstance()) {
     if (ObjCInterfaceDecl *OID = MDecl->getClassInterface()) {
       // There may be no interface context due to error in declaration of the 
       // interface (which has been reported). Recover gracefully
-      QualType selfTy = Context.getObjCInterfaceType(OID);
+      selfTy = Context.getObjCInterfaceType(OID);
       selfTy = Context.getPointerType(selfTy);
-      PI.TypeInfo = selfTy.getAsOpaquePtr();
     }
   }
-
-  CurMethodDecl->setSelfDecl(ActOnParamDeclarator(PI, FnBodyScope));
+  CurMethodDecl->setSelfDecl(CreateImplicitParameter(FnBodyScope, PI.Ident, 
+                                                     PI.IdentLoc, selfTy));
   
   PI.Ident = &Context.Idents.get("_cmd");
-  PI.TypeInfo = Context.getObjCSelType().getAsOpaquePtr();
-  ActOnParamDeclarator(PI, FnBodyScope);
-  
+  CreateImplicitParameter(FnBodyScope, PI.Ident, PI.IdentLoc, 
+                          Context.getObjCSelType());
+
+  // Introduce all of the othe parameters into this scope  
   for (unsigned i = 0, e = MDecl->getNumParams(); i != e; ++i) {
     ParmVarDecl *PDecl = MDecl->getParamDecl(i);
-    PI.Ident = PDecl->getIdentifier();
-    PI.IdentLoc = PDecl->getLocation(); // user vars have a real location.
-    PI.TypeInfo = PDecl->getType().getAsOpaquePtr();
-    MDecl->setParamDecl(i, ActOnParamDeclarator(PI, FnBodyScope));
+    IdentifierInfo *II = PDecl->getIdentifier();
+    if (II) {
+      PDecl->setNext(II->getFETokenInfo<ScopedDecl>());
+      II->setFETokenInfo(PDecl);
+      FnBodyScope->AddDecl(PDecl);
+    }
   }
 }
 
@@ -843,7 +842,7 @@ Sema::DeclTy *Sema::ActOnMethodDeclaration(
     ParmVarDecl* Param = ParmVarDecl::Create(Context, ObjCMethod,
                                              SourceLocation(/*FIXME*/),
                                              ArgNames[i], argType,
-                                             VarDecl::None, 0);
+                                             VarDecl::None, 0, 0);
     Param->setObjCDeclQualifier(
       CvtQTToAstBitMask(ArgQT[i].getObjCDeclQualifier()));
     Params.push_back(Param);
index f4ef2839855b803af6b164ec4f3d470449f4de88..6a6cd25575a00b855cf3377ac0072dc116ed0368 100644 (file)
@@ -15,6 +15,7 @@
 #include "SemaUtil.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/Parse/DeclSpec.h" 
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/LiteralSupport.h"
@@ -594,15 +595,25 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
   Expr *Fn = static_cast<Expr *>(fn);
   Expr **Args = reinterpret_cast<Expr**>(args);
   assert(Fn && "no function call expression");
-  
+  FunctionDecl *FDecl = NULL;
+  unsigned NumArgsPassed = NumArgs;
+
+  // Promote the function operand.
+  UsualUnaryConversions(Fn);
+
+  // If we're directly calling a function, get the declaration for
+  // that function.
+  if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
+    if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
+      FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
+
   // Make the call expr early, before semantic checks.  This guarantees cleanup
   // of arguments and function on error.
-  llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgs,
+  if (getLangOptions().CPlusPlus && FDecl && NumArgs < FDecl->getNumParams())
+    NumArgsPassed = FDecl->getNumParams();
+  llvm::OwningPtr<CallExpr> TheCall(new CallExpr(Fn, Args, NumArgsPassed,
                                                  Context.BoolTy, RParenLoc));
   
-  // Promote the function operand.
-  TheCall->setCallee(UsualUnaryConversions(Fn));
-  
   // C99 6.5.2.2p1 - "The expression that denotes the called function shall have
   // type pointer to function".
   const PointerType *PT = Fn->getType()->getAsPointerType();
@@ -623,11 +634,19 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
     unsigned NumArgsInProto = Proto->getNumArgs();
     unsigned NumArgsToCheck = NumArgs;
     
-    // If too few arguments are available, don't make the call.
-    if (NumArgs < NumArgsInProto)
-      return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
-                  Fn->getSourceRange());
-    
+    // If too few arguments are available (and we don't have default
+    // arguments for the remaining parameters), don't make the call.
+    if (NumArgs < NumArgsInProto) {
+      if (getLangOptions().CPlusPlus && 
+          FDecl &&
+          FDecl->getParamDecl(NumArgs)->getDefaultArg()) {
+        // Use default arguments for missing arguments
+        NumArgsToCheck = NumArgsInProto;
+      } else
+        return Diag(RParenLoc, diag::err_typecheck_call_too_few_args,
+                    Fn->getSourceRange());
+    }
+
     // If too many are passed and not variadic, error on the extras and drop
     // them.
     if (NumArgs > NumArgsInProto) {
@@ -644,8 +663,13 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
     
     // Continue to check argument types (even if we have too few/many args).
     for (unsigned i = 0; i != NumArgsToCheck; i++) {
-      Expr *Arg = Args[i];
       QualType ProtoArgType = Proto->getArgType(i);
+
+      Expr *Arg;
+      if (i < NumArgs) 
+        Arg = Args[i];
+      else 
+        Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i));
       QualType ArgType = Arg->getType();
 
       // Compute implicit casts from the operand to the formal argument type.
@@ -679,11 +703,8 @@ ActOnCallExpr(ExprTy *fn, SourceLocation LParenLoc,
   }
 
   // Do special checking on direct calls to functions.
-  if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
-    if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
-      if (FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl()))
-        if (CheckFunctionCall(FDecl, TheCall.get()))
-          return true;
+  if (FDecl && CheckFunctionCall(FDecl, TheCall.get()))
+    return true;
 
   return TheCall.take();
 }
index 725da223345950b1af3509001ad08a965fffe3bb..4393b80a66e3e53eaee6585207fbb743e29de228 100644 (file)
@@ -394,7 +394,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
         llvm::SmallVector<QualType, 16> ArgTys;
         
         for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
-          QualType ArgTy = QualType::getFromOpaquePtr(FTI.ArgInfo[i].TypeInfo);
+          QualType ArgTy = ((ParmVarDecl *)FTI.ArgInfo[i].Param)->getType();
           assert(!ArgTy.isNull() && "Couldn't parse type?");
           //
           // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
@@ -425,13 +425,13 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
             if (FTI.NumArgs != 1 || FTI.isVariadic) {
               Diag(DeclType.Loc, diag::err_void_only_param);
               ArgTy = Context.IntTy;
-              FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
+              ((ParmVarDecl *)FTI.ArgInfo[i].Param)->setType(ArgTy);
             } else if (FTI.ArgInfo[i].Ident) {
               // Reject, but continue to parse 'int(void abc)'.
               Diag(FTI.ArgInfo[i].IdentLoc,
                    diag::err_param_with_void_type);
               ArgTy = Context.IntTy;
-              FTI.ArgInfo[i].TypeInfo = ArgTy.getAsOpaquePtr();
+              ((ParmVarDecl *)FTI.ArgInfo[i].Param)->setType(ArgTy);
             } else {
               // Reject, but continue to parse 'float(const void)'.
               if (ArgTy.getCVRQualifiers())
@@ -504,39 +504,6 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
   return T.getAsOpaquePtr();
 }
 
-/// ActOnParamDeclaratorType - Called from Parser::ParseFunctionDeclarator()
-/// when analyzing function prototypes.
-///
-/// Note: parameters have identifiers, but we don't care about them here, we
-/// just want the type converted.
-///
-Sema::TypeResult Sema::ActOnParamDeclaratorType(Scope *S, Declarator &D) {
-  DeclSpec &DS = D.getDeclSpec();
-  
-  // Verify C99 6.7.5.3p2: The only SCS allowed is 'register'.
-  if (DS.getStorageClassSpec() != DeclSpec::SCS_unspecified &&
-      DS.getStorageClassSpec() != DeclSpec::SCS_register) {
-    Diag(DS.getStorageClassSpecLoc(),
-         diag::err_invalid_storage_class_in_func_decl);
-    DS.ClearStorageClassSpecs();
-  }
-  if (DS.isThreadSpecified()) {
-    Diag(DS.getThreadSpecLoc(),
-         diag::err_invalid_storage_class_in_func_decl);
-    DS.ClearStorageClassSpecs();
-  }
-  
-  
-  QualType T = GetTypeForDeclarator(D, S);
-  
-  assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
-
-  // In this context, we *do not* check D.getInvalidType(). If the declarator
-  // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
-  // though it will not reflect the user specified type.
-  return T.getAsOpaquePtr();
-}
-
 AttributeList *Sema::ProcessTypeAttributes(QualType &Result, AttributeList *AL){
   // Scan through and apply attributes to this type where it makes sense.  Some
   // attributes (such as __address_space__, __vector_size__, etc) apply to the
diff --git a/test/CodeGen/cxx-default-arg.cpp b/test/CodeGen/cxx-default-arg.cpp
new file mode 100644 (file)
index 0000000..957b60a
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: clang -emit-llvm %s
+
+// Note: define CLANG_GENERATE_KNOWN_GOOD and compile to generate code
+// that makes all of the defaulted arguments explicit. The resulting
+// byte code should be identical to the compilation without
+// CLANG_GENERATE_KNOWN_GOOD.
+#ifdef CLANG_GENERATE_KNOWN_GOOD
+#  define DEFARG(...) __VA_ARGS__
+#else
+#  define DEFARG(...)
+#endif
+
+extern int x;
+struct S { float x; float y; } s;
+double _Complex c;
+
+void f(int i = 0, int j = 1, int k = x, struct S t = s, double _Complex d = c);
+
+void g() {
+  f(0, 1, x, s DEFARG(, c));
+  f(0, 1, x DEFARG(, s, c));
+  f(0, 1 DEFARG(, x, s, c));
+  f(0 DEFARG(, 1, x, s, c));
+  f(DEFARG(0, 1, x, s, c));
+}
diff --git a/test/Sema/arg-scope-c99.c b/test/Sema/arg-scope-c99.c
new file mode 100644 (file)
index 0000000..2d386c4
--- /dev/null
@@ -0,0 +1,2 @@
+// RUN: clang -fsyntax-only -std=c99 -verify %s
+int bb(int sz, int ar[sz][sz]) { }
diff --git a/test/Sema/arg-scope.c b/test/Sema/arg-scope.c
new file mode 100644 (file)
index 0000000..fc2bb70
--- /dev/null
@@ -0,0 +1,5 @@
+// RUN: clang -fsyntax-only -verify %s
+int aa(int b, int x[sizeof b]) {}
+
+void foo(int i, int A[i]) {}
+
diff --git a/test/Sema/default1.c b/test/Sema/default1.c
new file mode 100644 (file)
index 0000000..a72d0ae
--- /dev/null
@@ -0,0 +1,2 @@
+// RUN: clang -fsyntax-only -verify %s
+void f(int i = 0); // expected-error {{C does not support default arguments}}
diff --git a/test/Sema/default1.cpp b/test/Sema/default1.cpp
new file mode 100644 (file)
index 0000000..fe019c8
--- /dev/null
@@ -0,0 +1,17 @@
+// RUN: clang -fsyntax-only -verify %s
+void f(int i);
+void f(int i = 0); // expected-error {{previous definition is here}}
+void f(int i = 17); // expected-error {{redefinition of default argument}}
+
+
+void g(int i, int j, int k = 3);
+void g(int i, int j = 2, int k);
+void g(int i = 1, int j, int k);
+
+void h(int i, int j = 2, int k = 3, 
+       int l, // expected-error {{missing default argument on parameter 'l'}}
+       int,   // expected-error {{missing default argument on parameter}}
+       int n);// expected-error {{missing default argument on parameter 'n'}}
+
+struct S { } s;
+void i(int = s) { } // expected-error {{incompatible type}}
diff --git a/test/Sema/default2.cpp b/test/Sema/default2.cpp
new file mode 100644 (file)
index 0000000..0fe04ab
--- /dev/null
@@ -0,0 +1,12 @@
+// RUN: clang -fsyntax-only -verify %s
+void f(int i, int j, int k = 3);
+void f(int i, int j = 2, int k);
+void f(int i = 1, int j, int k);
+
+void i()
+{
+  f();
+  f(0);
+  f(0, 1);
+  f(0, 1, 2);
+}