[cfe-commits] r58641 - in /cfe/trunk: include/clang/Basic/DiagnosticKinds.def lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaOverload.cpp test/SemaCXX/direct-initializer.cpp
Douglas Gregor
doug.gregor at gmail.com
Mon Nov 3 12:45:28 PST 2008
Author: dgregor
Date: Mon Nov 3 14:45:27 2008
New Revision: 58641
URL: http://llvm.org/viewvc/llvm-project?rev=58641&view=rev
Log:
Implicit support for direct initialization of objects of class type, e.g.,
X x(5, 7);
Modified:
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/SemaCXX/direct-initializer.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Nov 3 14:45:27 2008
@@ -835,6 +835,12 @@
"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")
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Nov 3 14:45:27 2008
@@ -418,7 +418,7 @@
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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Nov 3 14:45:27 2008
@@ -1621,11 +1621,37 @@
// 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
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Nov 3 14:45:27 2008
@@ -848,14 +848,21 @@
// 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Nov 3 14:45:27 2008
@@ -1435,12 +1435,13 @@
/// 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);
Modified: cfe/trunk/test/SemaCXX/direct-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/direct-initializer.cpp?rev=58641&r1=58640&r2=58641&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/direct-initializer.cpp (original)
+++ cfe/trunk/test/SemaCXX/direct-initializer.cpp Mon Nov 3 14:45:27 2008
@@ -8,3 +8,29 @@
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:}}
+}
More information about the cfe-commits
mailing list