Add support for C++ default arguments, and rework Parse-Sema
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
diff --git a/Driver/clang.cpp b/Driver/clang.cpp
index 397c27d..6c82f19 100644
--- a/Driver/clang.cpp
+++ b/Driver/clang.cpp
@@ -901,6 +901,11 @@
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 @@
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);
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 3bae5e2..bce65f9 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -246,15 +246,20 @@
/// 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 @@
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; }
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 357fb95..3c99321 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -127,6 +127,45 @@
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
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 4c0fd7a..e3f0273 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -91,6 +91,7 @@
STMT(60, CXXCastExpr , Expr)
STMT(61, CXXBoolLiteralExpr , Expr)
STMT(62, CXXThrowExpr , Expr)
+STMT(63, CXXDefaultArgExpr , Expr)
// Obj-C Expressions.
STMT(70, ObjCStringLiteral , Expr)
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 1de1b6b..611edf5 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -243,7 +243,6 @@
//===----------------------------------------------------------------------===//
// Parser Diagnostics
//===----------------------------------------------------------------------===//
-
DIAG(w_type_defaults_to_int, WARNING,
"type defaults to 'int'")
DIAG(w_no_declarators, WARNING,
@@ -314,7 +313,7 @@
"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 @@
"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,
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 83d1fea..fb180c2 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -107,6 +107,14 @@
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 @@
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 @@
SourceLocation RPLoc) {
return 0;
}
+
+ //===------------------------- C++ Declarations -------------------------===//
+ /// ActOnParamDefaultArgument - Parse default argument for function parameter
+ virtual void ActOnParamDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc,
+ ExprTy *defarg) {
+ }
//===------------------------- C++ Expressions --------------------------===//
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index e52f307..6204a38 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -416,14 +416,10 @@
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 {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e27015b..8228ece 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -224,9 +224,9 @@
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,
diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp
index bc5310c..14666d6 100644
--- a/lib/AST/DeclSerialization.cpp
+++ b/lib/AST/DeclSerialization.cpp
@@ -226,15 +226,16 @@
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;
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 5205702..0287aa0 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -337,6 +337,9 @@
if (getType()->isVoidType())
return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect();
return false;
+
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->hasLocalSideEffect();
}
}
@@ -401,6 +404,8 @@
return LV_Valid;
case PreDefinedExprClass:
return LV_Valid;
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue();
default:
break;
}
@@ -465,6 +470,8 @@
return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage();
case PreDefinedExprClass:
return true;
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage();
}
}
@@ -636,6 +643,8 @@
}
return true;
}
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->isConstantExpr(Ctx, Loc);
}
}
@@ -981,6 +990,9 @@
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 @@
// 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.
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 3bc32e7..03faf8b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -45,3 +45,11 @@
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;
+}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index ba82b7f..a76fd1f 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -658,6 +658,11 @@
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::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
+ // Nothing to print: we picked up the default argument
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp
index 41569df..7058c0c 100644
--- a/lib/AST/StmtSerialization.cpp
+++ b/lib/AST/StmtSerialization.cpp
@@ -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 @@
case ObjCStringLiteralClass:
return ObjCStringLiteral::CreateImpl(D, C);
+
+ //==--------------------------------------==//
+ // C++
+ //==--------------------------------------==//
+ case CXXDefaultArgExprClass:
+ return CXXDefaultArgExpr::CreateImpl(D, C);
+
}
}
@@ -1002,3 +1010,16 @@
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);
+}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 3bfcc10..b5c755a 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -86,6 +86,9 @@
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);
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 1e8c8a3..a486d6a 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -120,6 +120,9 @@
ComplexPairTy VisitUnaryExtension(const UnaryOperator *E) {
return Visit(E->getSubExpr());
}
+ ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ return Visit(DAE->getExpr());
+ }
struct BinOpInfo {
ComplexPairTy LHS;
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index e2405b8..2ca71c3 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -69,6 +69,10 @@
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;
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 8977907..2f03f88 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -169,7 +169,7 @@
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 @@
return Visit(E->getSubExpr());
}
Value *VisitUnaryOffsetOf(const UnaryOperator *E);
+ Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
+ return Visit(DAE->getExpr());
+ }
// Binary Operators.
Value *EmitMul(const BinOpInfo &Ops) {
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0eb5c1f..0eb95fa 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1232,8 +1232,10 @@
///
/// 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 @@
// 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 @@
// 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 @@
// 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 @@
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.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index cd99fc0..7e41bcc 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -509,6 +509,10 @@
// 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 @@
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 @@
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 @@
}
}
+ // Leave prototype scope.
+ ExitScope();
+
// The actions module must verify that all arguments were declared.
}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 70aaf24..b2a88eb 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -202,14 +202,16 @@
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 @@
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);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0f464a0..5451ec2 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -263,9 +263,10 @@
}
}
-/// 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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;
}
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index c94c681..a9efe6c 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -42,32 +42,31 @@
// 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 @@
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);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index f4ef283..6a6cd25 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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 @@
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 @@
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 @@
// 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 @@
}
// 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();
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 725da22..4393b80 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -394,7 +394,7 @@
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 @@
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 @@
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
index 0000000..957b60a
--- /dev/null
+++ b/test/CodeGen/cxx-default-arg.cpp
@@ -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
index 0000000..2d386c4
--- /dev/null
+++ b/test/Sema/arg-scope-c99.c
@@ -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
index 0000000..fc2bb70
--- /dev/null
+++ b/test/Sema/arg-scope.c
@@ -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
index 0000000..a72d0ae
--- /dev/null
+++ b/test/Sema/default1.c
@@ -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
index 0000000..fe019c8
--- /dev/null
+++ b/test/Sema/default1.cpp
@@ -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
index 0000000..0fe04ab
--- /dev/null
+++ b/test/Sema/default2.cpp
@@ -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);
+}