[cfe-commits] r58756 - in /cfe/trunk: lib/AST/DeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp test/SemaCXX/copy-initialization.cpp test/SemaCXX/direct-initializer.cpp
Douglas Gregor
doug.gregor at gmail.com
Wed Nov 5 07:29:39 PST 2008
Author: dgregor
Date: Wed Nov 5 09:29:30 2008
New Revision: 58756
URL: http://llvm.org/viewvc/llvm-project?rev=58756&view=rev
Log:
Implement C++ copy-initialization for declarations. There is now some
duplication in the handling of copy-initialization by constructor,
which occurs both for initialization of a declaration and for
overloading. The initialization code is due for some refactoring.
Added:
cfe/trunk/test/SemaCXX/copy-initialization.cpp (with props)
Modified:
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/test/SemaCXX/direct-initializer.cpp
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Nov 5 09:29:30 2008
@@ -158,7 +158,7 @@
// 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
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Nov 5 09:29:30 2008
@@ -708,11 +708,20 @@
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 @@
/// 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);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Nov 5 09:29:30 2008
@@ -627,7 +627,9 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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();
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Nov 5 09:29:30 2008
@@ -835,7 +835,6 @@
// Add this constructor to the set of constructors of the current
// class.
ClassDecl->addConstructor(Context, ConDecl);
-
return (DeclTy *)ConDecl;
}
@@ -960,15 +959,23 @@
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 @@
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 @@
// 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.
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Nov 5 09:29:30 2008
@@ -1231,7 +1231,8 @@
literalExpr->getSourceRange().getEnd()));
}
- if (CheckInitializerTypes(literalExpr, literalType))
+ if (CheckInitializerTypes(literalExpr, literalType, LParenLoc,
+ "temporary"))
return true;
bool isFileScope = !getCurFunctionDecl() && !getCurMethodDecl();
Added: cfe/trunk/test/SemaCXX/copy-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/copy-initialization.cpp?rev=58756&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/copy-initialization.cpp (added)
+++ cfe/trunk/test/SemaCXX/copy-initialization.cpp Wed Nov 5 09:29:30 2008
@@ -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'}}
+}
Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaCXX/copy-initialization.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaCXX/direct-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/direct-initializer.cpp?rev=58756&r1=58755&r2=58756&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/direct-initializer.cpp (original)
+++ cfe/trunk/test/SemaCXX/direct-initializer.cpp Wed Nov 5 09:29:30 2008
@@ -20,9 +20,9 @@
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 @@
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'}}
}
More information about the cfe-commits
mailing list