aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h21
-rw-r--r--include/clang/AST/ExprCXX.h4
-rw-r--r--include/clang/Basic/DiagnosticKinds.def4
-rw-r--r--include/clang/Parse/Action.h7
-rw-r--r--lib/AST/StmtDumper.cpp14
-rw-r--r--lib/AST/Type.cpp2
-rw-r--r--lib/Parse/ParseDecl.cpp8
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaDecl.cpp11
-rw-r--r--lib/Sema/SemaDeclCXX.cpp45
-rw-r--r--lib/Sema/SemaExpr.cpp15
-rw-r--r--test/SemaCXX/condition.cpp4
-rw-r--r--test/SemaCXX/constructor.cpp5
-rw-r--r--test/SemaCXX/copy-initialization.cpp2
-rw-r--r--test/SemaCXX/default1.cpp4
-rw-r--r--test/SemaCXX/default2.cpp12
16 files changed, 124 insertions, 36 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 8ff8aefaaf..0401c50454 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -504,6 +504,27 @@ public:
Expr *getDefaultArg() { return DefaultArg; }
void setDefaultArg(Expr *defarg) { DefaultArg = defarg; }
+ /// hasUnparsedDefaultArg - Determines whether this parameter has a
+ /// default argument that has not yet been parsed. This will occur
+ /// during the processing of a C++ class whose member functions have
+ /// default arguments, e.g.,
+ /// @code
+ /// class X {
+ /// public:
+ /// void f(int x = 17); // x has an unparsed default argument now
+ /// }; // x has a regular default argument now
+ /// @endcode
+ bool hasUnparsedDefaultArg() const {
+ return DefaultArg == reinterpret_cast<Expr *>(-1);
+ }
+
+ /// setUnparsedDefaultArg - Specify that this parameter has an
+ /// unparsed default argument. The argument will be replaced with a
+ /// real default argument via setDefaultArg when the class
+ /// definition enclosing the function declaration that owns this
+ /// default argument is completed.
+ void setUnparsedDefaultArg() { DefaultArg = reinterpret_cast<Expr *>(-1); }
+
QualType getOriginalType() const;
// Implement isa/cast/dyncast/etc.
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 31dfd25833..be33eb1939 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -335,7 +335,9 @@ public:
// Param is the parameter whose default argument is used by this
// expression.
explicit CXXDefaultArgExpr(ParmVarDecl *param)
- : Expr(CXXDefaultArgExprClass, param->getDefaultArg()->getType()),
+ : Expr(CXXDefaultArgExprClass,
+ param->hasUnparsedDefaultArg()? param->getType().getNonReferenceType()
+ : param->getDefaultArg()->getType()),
Param(param) { }
// Retrieve the parameter that the argument was created from.
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 7675710a34..321b2c69c5 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -1352,6 +1352,10 @@ DIAG(warn_value_always_false, WARNING,
// FIXME: %2 is an english string here.
DIAG(err_typecheck_convert_incompatible, ERROR,
"incompatible type %2 %1, expected %0")
+DIAG(err_cannot_initialize_decl_noname, ERROR,
+ "cannot initialize a value of type %0 with an %select{rvalue|lvalue}1 of type %2")
+DIAG(err_cannot_initialize_decl, ERROR,
+ "cannot initialize %0 with an %select{rvalue|lvalue}1 of type %2")
DIAG(warn_incompatible_qualified_id, WARNING,
"incompatible type %2 %1, expected %0")
DIAG(warn_incompatible_qualified_id_operands, WARNING,
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 39de870d12..13b3c8a2b7 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -734,6 +734,13 @@ public:
ExprTy *defarg) {
}
+ /// ActOnParamUnparsedDefaultArgument - We've seen a default
+ /// argument for a function parameter, but we can't parse it yet
+ /// because we're inside a class definition. Note that this default
+ /// argument will be parsed later.
+ virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc) { }
+
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
/// the default argument for the parameter param failed.
virtual void ActOnParamDefaultArgumentError(DeclTy *param) { }
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index f11536f9c2..c3ce92de60 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -83,12 +83,14 @@ namespace {
void DumpType(QualType T) {
fprintf(F, "'%s'", T.getAsString().c_str());
- // If the type is directly a typedef, strip off typedefness to give at
- // least one level of concreteness.
- if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
- QualType Simplified =
- TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
- fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+ if (!T.isNull()) {
+ // If the type is directly a typedef, strip off typedefness to give at
+ // least one level of concreteness.
+ if (TypedefType *TDT = dyn_cast<TypedefType>(T)) {
+ QualType Simplified =
+ TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers());
+ fprintf(F, ":'%s'", Simplified.getAsString().c_str());
+ }
}
}
void DumpStmt(const Stmt *Node) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 5909c976aa..c70ad4af52 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -841,7 +841,7 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
void QualType::getAsStringInternal(std::string &S) const {
if (isNull()) {
- S += "NULL TYPE\n";
+ S += "NULL TYPE";
return;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 16e7e774aa..213a210b9e 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1811,6 +1811,8 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
// ActOnParamDefaultArgument will reject the default argument in
// C.
if (Tok.is(tok::equal)) {
+ SourceLocation EqualLoc = Tok.getLocation();
+
// Parse the default argument
if (D.getContext() == Declarator::MemberContext) {
// If we're inside a class definition, cache the tokens
@@ -1824,10 +1826,12 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
tok::semi, false)) {
delete DefArgToks;
DefArgToks = 0;
- }
+ Actions.ActOnParamDefaultArgumentError(Param);
+ } else
+ Actions.ActOnParamUnparsedDefaultArgument(Param, EqualLoc);
} else {
// Consume the '='.
- SourceLocation EqualLoc = ConsumeToken();
+ ConsumeToken();
OwningExprResult DefArgResult(ParseAssignmentExpression());
if (DefArgResult.isInvalid()) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2664c57ee4..843e732e87 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -276,6 +276,8 @@ public:
virtual void ActOnParamDefaultArgument(DeclTy *param,
SourceLocation EqualLoc,
ExprTy *defarg);
+ virtual void ActOnParamUnparsedDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc);
virtual void ActOnParamDefaultArgumentError(DeclTy *param);
void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
void ActOnUninitializedDecl(DeclTy *dcl);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index d84d6adad0..c668959176 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -888,9 +888,14 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType,
if (!PerformImplicitConversion(Init, DeclType, "initializing"))
return false;
- return Diag(InitLoc, diag::err_typecheck_convert_incompatible)
- << DeclType << InitEntity << "initializing"
- << Init->getSourceRange();
+ if (InitEntity)
+ return Diag(InitLoc, diag::err_cannot_initialize_decl)
+ << InitEntity << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+ << Init->getType() << Init->getSourceRange();
+ else
+ return Diag(InitLoc, diag::err_cannot_initialize_decl_noname)
+ << DeclType << (int)(Init->isLvalue(Context) == Expr::LV_Valid)
+ << Init->getType() << Init->getSourceRange();
}
// C99 6.7.8p16.
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 918fd2ac9a..48373369bc 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -126,8 +126,9 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc,
// a declaration of a variable of the parameter type, using the
// copy-initialization semantics (8.5).
Expr *DefaultArgPtr = DefaultArg.get();
- bool DefaultInitFailed = PerformCopyInitialization(DefaultArgPtr, ParamType,
- "in default argument");
+ bool DefaultInitFailed = CheckInitializerTypes(DefaultArgPtr, ParamType,
+ EqualLoc,
+ Param->getDeclName());
if (DefaultArgPtr != DefaultArg.get()) {
DefaultArg.take();
DefaultArg.reset(DefaultArgPtr);
@@ -147,6 +148,17 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc,
Param->setDefaultArg(DefaultArg.take());
}
+/// ActOnParamUnparsedDefaultArgument - We've seen a default
+/// argument for a function parameter, but we can't parse it yet
+/// because we're inside a class definition. Note that this default
+/// argument will be parsed later.
+void Sema::ActOnParamUnparsedDefaultArgument(DeclTy *param,
+ SourceLocation EqualLoc) {
+ ParmVarDecl *Param = (ParmVarDecl*)param;
+ if (Param)
+ Param->setUnparsedDefaultArg();
+}
+
/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of
/// the default argument for the parameter param failed.
void Sema::ActOnParamDefaultArgumentError(DeclTy *param) {
@@ -171,16 +183,16 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
if (chunk.Kind == DeclaratorChunk::Function) {
for (unsigned argIdx = 0; argIdx < chunk.Fun.NumArgs; ++argIdx) {
ParmVarDecl *Param = (ParmVarDecl *)chunk.Fun.ArgInfo[argIdx].Param;
- if (Param->getDefaultArg()) {
- Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
- << Param->getDefaultArg()->getSourceRange();
- Param->setDefaultArg(0);
- } else if (CachedTokens *Toks
- = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens) {
+ if (Param->hasUnparsedDefaultArg()) {
+ CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
<< SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
delete Toks;
chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
+ } else if (Param->getDefaultArg()) {
+ Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
+ << Param->getDefaultArg()->getSourceRange();
+ Param->setDefaultArg(0);
}
}
}
@@ -269,7 +281,8 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) {
for (p = 0; p <= LastMissingDefaultArg; ++p) {
ParmVarDecl *Param = FD->getParamDecl(p);
if (Param->getDefaultArg()) {
- delete Param->getDefaultArg();
+ if (!Param->hasUnparsedDefaultArg())
+ Param->getDefaultArg()->Destroy(Context);
Param->setDefaultArg(0);
}
}
@@ -736,6 +749,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
ActOnFields(S, RLoc, TagDecl,
(DeclTy**)FieldCollector->getCurFields(),
FieldCollector->getCurNumFields(), LBrac, RBrac, 0);
+ AddImplicitlyDeclaredMembersToClass(cast<CXXRecordDecl>((Decl*)TagDecl));
}
/// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared
@@ -872,7 +886,6 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
void Sema::ActOnFinishCXXClassDef(DeclTy *D) {
CXXRecordDecl *Rec = cast<CXXRecordDecl>(static_cast<Decl *>(D));
FieldCollector->FinishClass();
- AddImplicitlyDeclaredMembersToClass(Rec);
PopDeclContext();
// Everything, including inline method definitions, have been parsed.
@@ -901,6 +914,12 @@ void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {
/// ActOnParamDefaultArgument event for this parameter.
void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) {
ParmVarDecl *Param = (ParmVarDecl*)ParamD;
+
+ // If this parameter has an unparsed default argument, clear it out
+ // to make way for the parsed default argument.
+ if (Param->hasUnparsedDefaultArg())
+ Param->setDefaultArg(0);
+
S->AddDecl(Param);
if (Param->getDeclName())
IdResolver.AddDecl(Param);
@@ -1871,7 +1890,11 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
if (Op != OO_Call) {
for (FunctionDecl::param_iterator Param = FnDecl->param_begin();
Param != FnDecl->param_end(); ++Param) {
- if (Expr *DefArg = (*Param)->getDefaultArg())
+ if ((*Param)->hasUnparsedDefaultArg())
+ return Diag((*Param)->getLocation(),
+ diag::err_operator_overload_default_arg)
+ << FnDecl->getDeclName();
+ else if (Expr *DefArg = (*Param)->getDefaultArg())
return Diag((*Param)->getLocation(),
diag::err_operator_overload_default_arg)
<< FnDecl->getDeclName() << DefArg->getSourceRange();
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4088f443f7..d65c10bb50 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1507,16 +1507,17 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn,
QualType ProtoArgType = Proto->getArgType(i);
Expr *Arg;
- if (i < NumArgs)
+ if (i < NumArgs) {
Arg = Args[i];
- else
+
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
+ return true;
+ } else
+ // We already type-checked the argument, so we know it works.
Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i));
QualType ArgType = Arg->getType();
-
- // Pass the argument.
- if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
- return true;
-
+
Call->setArg(i, Arg);
}
diff --git a/test/SemaCXX/condition.cpp b/test/SemaCXX/condition.cpp
index d611364cf0..43117e61c3 100644
--- a/test/SemaCXX/condition.cpp
+++ b/test/SemaCXX/condition.cpp
@@ -16,8 +16,8 @@ void test() {
for (;s;) ; // expected-error {{expression must have bool type (or be convertible to bool) ('struct S' invalid)}}
switch (s) {} // expected-error {{statement requires expression of integer type ('struct S' invalid)}}
- while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}}
- while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}} expected-error {{expression must have bool type}}
+ while (struct S {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
+ while (struct {} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{cannot initialize 'x' with an rvalue of type 'int'}} expected-error {{expression must have bool type}}
switch (enum {E} x=0) ; // expected-error {{types may not be defined in conditions}} expected-error {{incompatible type}}
if (int x=0) { // expected-note {{previous definition is here}}
diff --git a/test/SemaCXX/constructor.cpp b/test/SemaCXX/constructor.cpp
index 536593d512..68099ecac9 100644
--- a/test/SemaCXX/constructor.cpp
+++ b/test/SemaCXX/constructor.cpp
@@ -1,5 +1,4 @@
// RUN: clang -fsyntax-only -verify %s
-
typedef int INT;
class Foo {
@@ -37,3 +36,7 @@ struct y {
y(int);
};
extern y b;
+
+struct Length {
+ Length l() const { return *this; }
+};
diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp
index 5ef84de9ac..e380cc1ad3 100644
--- a/test/SemaCXX/copy-initialization.cpp
+++ b/test/SemaCXX/copy-initialization.cpp
@@ -13,5 +13,5 @@ void f(Y y, int *ip, float *fp) {
X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidate is:}}
X x2 = 0;
X x3 = ip;
- X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}}
+ X x4 = fp; // expected-error{{cannot initialize 'x4' with an lvalue of type 'float *'}}
}
diff --git a/test/SemaCXX/default1.cpp b/test/SemaCXX/default1.cpp
index 286be6106b..28444207d8 100644
--- a/test/SemaCXX/default1.cpp
+++ b/test/SemaCXX/default1.cpp
@@ -26,4 +26,6 @@ struct Y {
explicit Y(int);
};
-void k(Y y = 17); // expected-error{{incompatible type in default argument}}
+void k(Y y = 17); // expected-error{{cannot initialize 'y' with an rvalue of type 'int'}}
+
+void kk(Y = 17); // expected-error{{cannot initialize a value of type 'struct Y' with an rvalue of type 'int'}}
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index 863ac0e25f..c2873af3f0 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -103,8 +103,20 @@ public:
Z z2; // expected-error{{no matching constructor for initialization}}
Z z3(z);
}
+
+ void test_Z(const Z& z) {
+ Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
+ }
};
void test_Z(const Z& z) {
Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}
}
+
+struct ZZ {
+ void f(ZZ z = g()); // expected-error{{no matching constructor for initialization}}
+
+ static ZZ g(int = 17);
+
+ ZZ(ZZ&, int = 17); // expected-note{{candidate function}}
+};