diff options
-rw-r--r-- | lib/AST/DeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 20 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 69 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 72 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/copy-initialization.cpp | 17 | ||||
-rw-r--r-- | test/SemaCXX/direct-initializer.cpp | 6 |
7 files changed, 143 insertions, 46 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9f20ac8163..f49b207b0c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -158,7 +158,7 @@ bool CXXConstructorDecl::isDefaultConstructor() const { // A default constructor for a class X is a constructor of class // X that can be called without an argument. return (getNumParams() == 0) || - (getNumParams() > 0 & getParamDecl(1)->getDefaultArg() != 0); + (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0); } bool diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 72b56deca3..d14c5ffa20 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -708,11 +708,20 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); + /// InitializationKind - Represents which kind of C++ initialization + /// [dcl.init] a routine is to perform. + enum InitializationKind { + IK_Direct, ///< Direct initialization + IK_Copy, ///< Copy initialization + IK_Default ///< Default initialization + }; + CXXConstructorDecl * - PerformDirectInitForClassType(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, SourceRange Range, - std::string InitEntity, bool HasInitializer); + PerformInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, SourceRange Range, + std::string InitEntity, + InitializationKind Kind); /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -1146,7 +1155,8 @@ private: /// type checking declaration initializers (C99 6.7.8) friend class InitListChecker; - bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType); + bool CheckInitializerTypes(Expr *&simpleInit_or_initList, QualType &declType, + SourceLocation InitLoc, std::string InitEntity); bool CheckSingleInitializer(Expr *&simpleInit, QualType declType); bool CheckForConstantInitializer(Expr *e, QualType t); bool CheckArithmeticConstantExpression(const Expr* e); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a10470e0d4..5dc571c0ee 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -627,7 +627,9 @@ StringLiteral *Sema::IsStringLiteralInit(Expr *Init, QualType DeclType) { return 0; } -bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { +bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType, + SourceLocation InitLoc, + std::string InitEntity) { // C++ [dcl.init.ref]p1: // A variable declared to be a T&, that is “reference to type T” // (8.3.2), shall be initialized by an object, or function, of @@ -638,7 +640,7 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { // C99 6.7.8p3: The type of the entity to be initialized shall be an array // of unknown size ("[]") or an object type that is not a variable array type. if (const VariableArrayType *VAT = Context.getAsVariableArrayType(DeclType)) - return Diag(VAT->getSizeExpr()->getLocStart(), + return Diag(InitLoc, diag::err_variable_object_no_init, VAT->getSizeExpr()->getSourceRange()); @@ -648,6 +650,50 @@ bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) { if (StringLiteral *strLiteral = IsStringLiteralInit(Init, DeclType)) return CheckStringLiteralInit(strLiteral, DeclType); + // C++ [dcl.init]p14: + // -- If the destination type is a (possibly cv-qualified) class + // type: + if (getLangOptions().CPlusPlus && DeclType->isRecordType()) { + QualType DeclTypeC = Context.getCanonicalType(DeclType); + QualType InitTypeC = Context.getCanonicalType(Init->getType()); + + // -- If the initialization is direct-initialization, or if it is + // copy-initialization where the cv-unqualified version of the + // source type is the same class as, or a derived class of, the + // class of the destination, constructors are considered. + if ((DeclTypeC.getUnqualifiedType() == InitTypeC.getUnqualifiedType()) || + IsDerivedFrom(InitTypeC, DeclTypeC)) { + CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(DeclType, &Init, 1, + InitLoc, Init->getSourceRange(), + InitEntity, IK_Copy); + return Constructor == 0; + } + + // -- Otherwise (i.e., for the remaining copy-initialization + // cases), user-defined conversion sequences that can + // convert from the source type to the destination type or + // (when a conversion function is used) to a derived class + // thereof are enumerated as described in 13.3.1.4, and the + // best one is chosen through overload resolution + // (13.3). If the conversion cannot be done or is + // ambiguous, the initialization is ill-formed. The + // function selected is called with the initializer + // expression as its argument; if the function is a + // constructor, the call initializes a temporary of the + // destination type. + // FIXME: We're pretending to do copy elision here; return to + // this when we have ASTs for such things. + if (PerformImplicitConversion(Init, DeclType)) + return Diag(InitLoc, + diag::err_typecheck_convert_incompatible, + DeclType.getAsString(), InitEntity, + "initializing", + Init->getSourceRange()); + else + return false; + } + // C99 6.7.8p16. if (DeclType->isArrayType()) return Diag(Init->getLocStart(), @@ -1574,7 +1620,8 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); } else if (!VDecl->isInvalidDecl()) { - if (CheckInitializerTypes(Init, DclT)) + if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getName())) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -1587,7 +1634,8 @@ void Sema::AddInitializerToDecl(DeclTy *dcl, ExprTy *init) { if (VDecl->getStorageClass() == VarDecl::Extern) Diag(VDecl->getLocation(), diag::warn_extern_init); if (!VDecl->isInvalidDecl()) - if (CheckInitializerTypes(Init, DclT)) + if (CheckInitializerTypes(Init, DclT, VDecl->getLocation(), + VDecl->getName())) VDecl->setInvalidDecl(); // C++ 3.6.2p2, allow dynamic initialization of static initializers. @@ -1642,12 +1690,13 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) { if (const ArrayType *Array = Context.getAsArrayType(Type)) InitType = Array->getElementType(); if (InitType->isRecordType()) { - CXXConstructorDecl *Constructor - = PerformDirectInitForClassType(InitType, 0, 0, Var->getLocation(), - SourceRange(Var->getLocation(), - Var->getLocation()), - Var->getName(), - /*HasInitializer=*/false); + const CXXConstructorDecl *Constructor + = PerformInitializationByConstructor(InitType, 0, 0, + Var->getLocation(), + SourceRange(Var->getLocation(), + Var->getLocation()), + Var->getName(), + IK_Default); if (!Constructor) Var->setInvalidDecl(); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 95d17fa327..b95ebf0bad 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -835,7 +835,6 @@ Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) { // Add this constructor to the set of constructors of the current // class. ClassDecl->addConstructor(Context, ConDecl); - return (DeclTy *)ConDecl; } @@ -960,15 +959,23 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc, if (VDecl->getType()->isRecordType()) { CXXConstructorDecl *Constructor - = PerformDirectInitForClassType(DeclInitType, (Expr **)ExprTys, NumExprs, - VDecl->getLocation(), - SourceRange(VDecl->getLocation(), - RParenLoc), - VDecl->getName(), - /*HasInitializer=*/true); + = PerformInitializationByConstructor(DeclInitType, + (Expr **)ExprTys, NumExprs, + VDecl->getLocation(), + SourceRange(VDecl->getLocation(), + RParenLoc), + VDecl->getName(), + IK_Direct); if (!Constructor) { RealDecl->setInvalidDecl(); } + + // Let clients know that initialization was done with a direct + // initializer. + VDecl->setCXXDirectInitializer(true); + + // FIXME: Add ExprTys and Constructor to the RealDecl as part of + // the initializer. return; } @@ -987,21 +994,26 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc, AddInitializerToDecl(Dcl, ExprTys[0]); } -/// PerformDirectInitForClassType - Perform direct-initialization (C++ -/// [dcl.init]) for a value of the given class type with the given set -/// of arguments (@p Args). @p Loc is the location in the source code -/// where the initializer occurs (e.g., a declaration, member -/// initializer, functional cast, etc.) while @p Range covers the -/// whole initialization. @p HasInitializer is true if the initializer -/// was actually written in the source code. When successful, returns +/// PerformInitializationByConstructor - Perform initialization by +/// constructor (C++ [dcl.init]p14), which may occur as part of +/// direct-initialization or copy-initialization. We are initializing +/// an object of type @p ClassType with the given arguments @p +/// Args. @p Loc is the location in the source code where the +/// initializer occurs (e.g., a declaration, member initializer, +/// functional cast, etc.) while @p Range covers the whole +/// initialization. @p InitEntity is the entity being initialized, +/// which may by the name of a declaration or a type. @p Kind is the +/// kind of initialization we're performing, which affects whether +/// explicit constructors will be considered. When successful, returns /// the constructor that will be used to perform the initialization; -/// when the initialization fails, emits a diagnostic and returns null. +/// when the initialization fails, emits a diagnostic and returns +/// null. CXXConstructorDecl * -Sema::PerformDirectInitForClassType(QualType ClassType, - Expr **Args, unsigned NumArgs, - SourceLocation Loc, SourceRange Range, - std::string InitEntity, - bool HasInitializer) { +Sema::PerformInitializationByConstructor(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, SourceRange Range, + std::string InitEntity, + InitializationKind Kind) { const RecordType *ClassRec = ClassType->getAsRecordType(); assert(ClassRec && "Can only initialize a class type here"); @@ -1017,15 +1029,23 @@ Sema::PerformDirectInitForClassType(QualType ClassType, // with the initializer expression(s) as its argument(s). If no // constructor applies, or the overload resolution is ambiguous, // the initialization is ill-formed. - // - // FIXME: We don't check cv-qualifiers on the class type, because we - // don't yet keep track of whether a class type is a POD class type - // (or a "trivial" class type, as is used in C++0x). const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(ClassRec->getDecl()); OverloadCandidateSet CandidateSet; + + // Add constructors to the overload set. + OverloadedFunctionDecl *Constructors + = const_cast<OverloadedFunctionDecl *>(ClassDecl->getConstructors()); + for (OverloadedFunctionDecl::function_iterator Con + = Constructors->function_begin(); + Con != Constructors->function_end(); ++Con) { + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if ((Kind == IK_Direct) || + (Kind == IK_Copy && Constructor->isConvertingConstructor()) || + (Kind == IK_Default && Constructor->isDefaultConstructor())) + AddOverloadCandidate(Constructor, Args, NumArgs, CandidateSet); + } + OverloadCandidateSet::iterator Best; - AddOverloadCandidates(ClassDecl->getConstructors(), Args, NumArgs, - CandidateSet); switch (BestViableFunction(CandidateSet, Best)) { case OR_Success: // We found a constructor. Return it. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c0abc9e51a..80ecf3312a 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1231,7 +1231,8 @@ ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty, literalExpr->getSourceRange().getEnd())); } - if (CheckInitializerTypes(literalExpr, literalType)) + if (CheckInitializerTypes(literalExpr, literalType, LParenLoc, + "temporary")) return true; bool isFileScope = !getCurFunctionDecl() && !getCurMethodDecl(); diff --git a/test/SemaCXX/copy-initialization.cpp b/test/SemaCXX/copy-initialization.cpp new file mode 100644 index 0000000000..17028da069 --- /dev/null +++ b/test/SemaCXX/copy-initialization.cpp @@ -0,0 +1,17 @@ +// RUN: clang -fsyntax-only -verify %s + +class X { +public: + explicit X(const X&); + X(int*); // expected-note{{candidate function}} + explicit X(float*); +}; + +class Y : public X { }; + +void f(Y y, int *ip, float *fp) { + X x1 = y; // expected-error{{no matching constructor for initialization of 'x1'; candidates are:}} + X x2 = 0; + X x3 = ip; + X x4 = fp; // expected-error{{incompatible type initializing 'x4', expected 'class X'}} +} diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp index 952e132299..d5b91bb2b7 100644 --- a/test/SemaCXX/direct-initializer.cpp +++ b/test/SemaCXX/direct-initializer.cpp @@ -20,9 +20,9 @@ public: X(float, Y); // expected-note{{candidate function}} }; -class Z { // expected-note{{candidate function}} +class Z { public: - Z(int); // expected-note{{candidate function}} + Z(int); }; void g() { @@ -32,5 +32,5 @@ void g() { Y y(1.0); X x4(3.14, y); - Z z; // expected-error{{no matching constructor for initialization of 'z'; candidates are:}} + Z z; // expected-error{{no matching constructor for initialization of 'z'}} } |