diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-11-03 20:45:27 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-11-03 20:45:27 +0000 |
commit | 18fe56863be253a27b940022d27a3101778adaf6 (patch) | |
tree | b2cf207b1ee2380ade5236d92c0e9758090f2946 | |
parent | 4fd7ffe4c990357cec0c74f216cacc9825e46048 (diff) |
Implicit support for direct initialization of objects of class type, e.g.,
X x(5, 7);
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58641 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 6 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 28 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 84 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 5 | ||||
-rw-r--r-- | test/SemaCXX/direct-initializer.cpp | 26 |
6 files changed, 147 insertions, 10 deletions
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index db4f2f4c93..3ce3d8d9a2 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -835,6 +835,12 @@ DIAG(err_ovl_ambiguous_call, ERROR, "call to '%0' is ambiguous; candidates are:") DIAG(err_ovl_candidate, NOTE, "candidate function") +DIAG(err_ovl_no_viable_function_in_init, ERROR, + "no matching constructor for initialization of '%0'.") +DIAG(err_ovl_no_viable_function_in_init_with_cands, ERROR, + "no matching constructor for initialization of '%0'; candidates are:") +DIAG(err_ovl_ambiguous_init, ERROR, + "call to constructor of '%0' is ambiguous; candidates are:") DIAG(err_unexpected_typedef, ERROR, "unexpected type name '%0': expected expression") diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1b08a45fe8..dd7fe01bf0 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -418,7 +418,7 @@ private: Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); - void AddOverloadCandidates(OverloadedFunctionDecl *Ovl, + void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false); @@ -710,6 +710,12 @@ public: SourceLocation *CommaLocs, SourceLocation RParenLoc); + CXXConstructorDecl * + PerformDirectInitForClassType(QualType ClassType, + Expr **Args, unsigned NumArgs, + SourceLocation Loc, SourceRange Range, + std::string InitEntity, bool HasInitializer); + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, TypeTy *Ty, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 16053cecdb..a10470e0d4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1621,11 +1621,37 @@ void Sema::ActOnUninitializedDecl(DeclTy *dcl) { // function return type, in the declaration of a class member // within its class declaration (9.2), and where the extern // specifier is explicitly used. - if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) + if (Type->isReferenceType() && Var->getStorageClass() != VarDecl::Extern) { Diag(Var->getLocation(), diag::err_reference_var_requires_init, Var->getName(), SourceRange(Var->getLocation(), Var->getLocation())); + Var->setInvalidDecl(); + return; + } + + // C++ [dcl.init]p9: + // + // If no initializer is specified for an object, and the object + // is of (possibly cv-qualified) non-POD class type (or array + // thereof), the object shall be default-initialized; if the + // object is of const-qualified type, the underlying class type + // shall have a user-declared default constructor. + if (getLangOptions().CPlusPlus) { + QualType InitType = Type; + 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); + if (!Constructor) + Var->setInvalidDecl(); + } + } #if 0 // FIXME: Temporarily disabled because we are not properly parsing diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1100e700c9..9c1e4a949f 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -848,14 +848,21 @@ void Sema::AddCXXDirectInitializerToDecl(DeclTy *Dcl, SourceLocation LParenLoc, // The form of initialization (using parentheses or '=') is generally // insignificant, but does matter when the entity being initialized has a // class type. + QualType DeclInitType = VDecl->getType(); + if (const ArrayType *Array = Context.getAsArrayType(DeclInitType)) + DeclInitType = Array->getElementType(); if (VDecl->getType()->isRecordType()) { - // FIXME: When constructors for class types are supported, determine how - // exactly semantic checking will be done for direct initializers. - unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, - "initialization for class types is not handled yet"); - Diag(VDecl->getLocation(), DiagID); - RealDecl->setInvalidDecl(); + CXXConstructorDecl *Constructor + = PerformDirectInitForClassType(DeclInitType, (Expr **)ExprTys, NumExprs, + VDecl->getLocation(), + SourceRange(VDecl->getLocation(), + RParenLoc), + VDecl->getName(), + /*HasInitializer=*/true); + if (!Constructor) { + RealDecl->setInvalidDecl(); + } return; } @@ -874,6 +881,71 @@ 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 +/// the constructor that will be used to perform the initialization; +/// 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) { + const RecordType *ClassRec = ClassType->getAsRecordType(); + assert(ClassRec && "Can only initialize a class type here"); + + // C++ [dcl.init]p14: + // + // 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. The + // applicable constructors are enumerated (13.3.1.3), and the + // best one is chosen through overload resolution (13.3). The + // constructor so selected is called to initialize the object, + // 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; + OverloadCandidateSet::iterator Best; + AddOverloadCandidates(ClassDecl->getConstructors(), Args, NumArgs, + CandidateSet); + switch (BestViableFunction(CandidateSet, Best)) { + case OR_Success: + // We found a constructor. Return it. + return cast<CXXConstructorDecl>(Best->Function); + + case OR_No_Viable_Function: + if (CandidateSet.empty()) + Diag(Loc, diag::err_ovl_no_viable_function_in_init, + InitEntity, Range); + else { + Diag(Loc, diag::err_ovl_no_viable_function_in_init_with_cands, + InitEntity, Range); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false); + } + return 0; + + case OR_Ambiguous: + Diag(Loc, diag::err_ovl_ambiguous_init, + InitEntity, Range); + PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true); + return 0; + } + + return 0; +} + /// CompareReferenceRelationship - Compare the two types T1 and T2 to /// determine whether they are reference-related, /// reference-compatible, reference-compatible with added diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 1c2f20b26b..4f02065bb1 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1435,12 +1435,13 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, /// AddOverloadCandidates - Add all of the function overloads in Ovl /// to the candidate set. void -Sema::AddOverloadCandidates(OverloadedFunctionDecl *Ovl, +Sema::AddOverloadCandidates(const OverloadedFunctionDecl *Ovl, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { - for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(); + for (OverloadedFunctionDecl::function_const_iterator Func + = Ovl->function_begin(); Func != Ovl->function_end(); ++Func) AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet, SuppressUserConversions); diff --git a/test/SemaCXX/direct-initializer.cpp b/test/SemaCXX/direct-initializer.cpp index c756e473dd..952e132299 100644 --- a/test/SemaCXX/direct-initializer.cpp +++ b/test/SemaCXX/direct-initializer.cpp @@ -8,3 +8,29 @@ void f() { int (x2)(1); // expected-warning {{statement was disambiguated as declaration}} for (int x(1);;) {} } + +class Y { + explicit Y(float); +}; + +class X { // expected-note{{candidate function}} +public: + explicit X(int); // expected-note{{candidate function}} + X(float, float, float); // expected-note{{candidate function}} + X(float, Y); // expected-note{{candidate function}} +}; + +class Z { // expected-note{{candidate function}} +public: + Z(int); // expected-note{{candidate function}} +}; + +void g() { + X x1(5); + X x2(1.0, 3, 4.2); + X x3(1.0, 1.0); // expected-error{{no matching constructor for initialization of 'x3'; candidates are:}} + Y y(1.0); + X x4(3.14, y); + + Z z; // expected-error{{no matching constructor for initialization of 'z'; candidates are:}} +} |