[cfe-commits] r58353 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h lib/AST/Expr.cpp lib/Parse/ParseDecl.cpp lib/Sema/Sema.h lib/Sema/SemaChecking.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaInherit.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaStmt.cpp test/Parser/cxx-reference.cpp test/SemaCXX/overload-call.cpp test/SemaCXX/references.cpp
Douglas Gregor
doug.gregor at gmail.com
Tue Oct 28 17:14:01 PDT 2008
Author: dgregor
Date: Tue Oct 28 19:13:59 2008
New Revision: 58353
URL: http://llvm.org/viewvc/llvm-project?rev=58353&view=rev
Log:
Implement initialization of a reference (C++ [dcl.init.ref]) as part
of copy initialization. Other pieces of the puzzle:
- Try/Perform-ImplicitConversion now handles implicit conversions
that don't involve references.
- Try/Perform-CopyInitialization uses
CheckSingleAssignmentConstraints for C. PerformCopyInitialization
is now used for all argument passing and returning values from a
function.
- Diagnose errors with declaring references and const values without
an initializer. (Uses a new Action callback, ActOnUninitializedDecl).
We do not yet have implicit conversion sequences for reference
binding, which means that we don't have any overloading support for
reference parameters yet.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaInherit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaStmt.cpp
cfe/trunk/test/Parser/cxx-reference.cpp
cfe/trunk/test/SemaCXX/overload-call.cpp
cfe/trunk/test/SemaCXX/references.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Tue Oct 28 19:13:59 2008
@@ -105,6 +105,7 @@
isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx) const;
bool isNullPointerConstant(ASTContext &Ctx) const;
+ bool isBitField();
/// getIntegerConstantExprValue() - Return the value of an integer
/// constant expression. The expression must be a valid integer
@@ -153,7 +154,7 @@
Expr* IgnoreParens();
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
- /// or CastExprs or ImplicitCastExprs, returning their operand.
+ /// or CastExprs, returning their operand.
Expr *IgnoreParenCasts();
const Expr* IgnoreParens() const {
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Tue Oct 28 19:13:59 2008
@@ -676,6 +676,16 @@
DIAG(err_member_initialization, ERROR,
"'%0' can only be initialized if it is a static const integral data member")
+// C++ initialization
+DIAG(err_not_reference_to_const_init, ERROR,
+ "non-const reference to type '%0' cannot be initialized with a %1 of type '%2'")
+DIAG(err_reference_init_drops_quals, ERROR,
+ "initialization of reference to type '%0' with a %1 of type '%2' drops qualifiers")
+DIAG(err_reference_var_requires_init, ERROR,
+ "declaration of reference variable '%0' requires an initializer")
+DIAG(err_const_var_requires_init, ERROR,
+ "declaration of const variable '%0' requires an initializer")
+
// Attributes
DIAG(err_attribute_wrong_number_arguments, ERROR,
"attribute requires %0 argument(s)")
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Tue Oct 28 19:13:59 2008
@@ -130,6 +130,13 @@
virtual void AddInitializerToDecl(DeclTy *Dcl, ExprTy *Init) {
return;
}
+
+ /// ActOnUninitializedDecl - This action is called immediately after
+ /// ActOnDeclarator (when an initializer is *not* present).
+ virtual void ActOnUninitializedDecl(DeclTy *Dcl) {
+ return;
+ }
+
/// FinalizeDeclaratorGroup - After a sequence of declarators are parsed, this
/// gives the actions implementation a chance to process the group as a whole.
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group) {
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 28 19:13:59 2008
@@ -397,8 +397,7 @@
// C++ [expr.call]p10:
// A function call is an lvalue if and only if the result type
// is a reference.
- QualType CalleeType
- = cast<CallExpr>(this)->getCallee()->IgnoreParens()->getType();
+ QualType CalleeType = cast<CallExpr>(this)->getCallee()->getType();
if (const PointerType *FnTypePtr = CalleeType->getAsPointerType())
if (const FunctionType *FnType
= FnTypePtr->getPointeeType()->getAsFunctionType())
@@ -1106,6 +1105,14 @@
return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0;
}
+/// isBitField - Return true if this expression is a bit-field.
+bool Expr::isBitField() {
+ Expr *E = this->IgnoreParenCasts();
+ if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E))
+ return MemRef->getMemberDecl()->isBitField();
+ return false;
+}
+
unsigned ExtVectorElementExpr::getNumElements() const {
if (const VectorType *VT = getType()->getAsVectorType())
return VT->getNumElements();
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Oct 28 19:13:59 2008
@@ -310,6 +310,8 @@
&Exprs[0], Exprs.size(),
&CommaLocs[0], RParenLoc);
}
+ } else {
+ Actions.ActOnUninitializedDecl(LastDeclInGroup);
}
// If we don't have a comma, it is either the end of the list (a ';') or an
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Oct 28 19:13:59 2008
@@ -279,6 +279,7 @@
SourceLocation EqualLoc,
ExprTy *defarg);
void AddInitializerToDecl(DeclTy *dcl, ExprTy *init);
+ void ActOnUninitializedDecl(DeclTy *dcl);
virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
virtual DeclTy *ActOnStartOfFunctionDef(Scope *S, Declarator &D);
@@ -369,7 +370,7 @@
/// C++ Overloading.
bool IsOverload(FunctionDecl *New, Decl* OldD,
OverloadedFunctionDecl::function_iterator &MatchedDecl);
- ImplicitConversionSequence TryCopyInitialization(Expr* From, QualType ToType);
+ ImplicitConversionSequence TryImplicitConversion(Expr* From, QualType ToType);
bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType);
bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
@@ -393,6 +394,10 @@
CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,
const StandardConversionSequence& SCS2);
+ ImplicitConversionSequence TryCopyInitialization(Expr* From, QualType ToType);
+ bool PerformCopyInitialization(Expr *&From, QualType ToType,
+ const char *Flavor);
+
/// OverloadingResult - Capture the result of performing overload
/// resolution.
enum OverloadingResult {
@@ -1111,6 +1116,34 @@
StringLiteral *IsStringLiteralInit(Expr *Init, QualType DeclType);
bool CheckStringLiteralInit(StringLiteral *strLiteral, QualType &DeclT);
+ // type checking C++ declaration initializers (C++ [dcl.init]).
+
+ /// ReferenceCompareResult - Expresses the result of comparing two
+ /// types (cv1 T1 and cv2 T2) to determine their compatibility for the
+ /// purposes of initialization by reference (C++ [dcl.init.ref]p4).
+ enum ReferenceCompareResult {
+ /// Ref_Incompatible - The two types are incompatible, so direct
+ /// reference binding is not possible.
+ Ref_Incompatible = 0,
+ /// Ref_Related - The two types are reference-related, which means
+ /// that their unqualified forms (T1 and T2) are either the same
+ /// or T1 is a base class of T2.
+ Ref_Related,
+ /// Ref_Compatible_With_Added_Qualification - The two types are
+ /// reference-compatible with added qualification, meaning that
+ /// they are reference-compatible and the qualifiers on T1 (cv1)
+ /// are greater than the qualifiers on T2 (cv2).
+ Ref_Compatible_With_Added_Qualification,
+ /// Ref_Compatible - The two types are reference-compatible and
+ /// have equivalent qualifiers (cv1 == cv2).
+ Ref_Compatible
+ };
+
+ ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2);
+
+ bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
+ bool Complain = true);
+
/// CheckCastTypes - Check type constraints for casting between types.
bool CheckCastTypes(SourceRange TyRange, QualType CastTy, Expr *&CastExpr);
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Tue Oct 28 19:13:59 2008
@@ -886,7 +886,7 @@
DeclRefExpr *DR = cast<DeclRefExpr>(E);
if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
- if(V->hasLocalStorage()) return DR;
+ if(V->hasLocalStorage() && !V->getType()->isReferenceType()) return DR;
return NULL;
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Oct 28 19:13:59 2008
@@ -628,6 +628,13 @@
}
bool Sema::CheckInitializerTypes(Expr *&Init, QualType &DeclType) {
+ // 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
+ // type T or by an object that can be converted into a T.
+ if (DeclType->isReferenceType())
+ return CheckReferenceInit(Init, 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))
@@ -1516,6 +1523,49 @@
return;
}
+void Sema::ActOnUninitializedDecl(DeclTy *dcl) {
+ Decl *RealDecl = static_cast<Decl *>(dcl);
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) {
+ QualType Type = Var->getType();
+ // C++ [dcl.init.ref]p3:
+ // The initializer can be omitted for a reference only in a
+ // parameter declaration (8.3.5), in the declaration of a
+ // 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)
+ Diag(Var->getLocation(),
+ diag::err_reference_var_requires_init,
+ Var->getName(),
+ SourceRange(Var->getLocation(), Var->getLocation()));
+
+ // 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. Otherwise, if no initializer is specified for
+ // an object, the object and its subobjects, if any, have an
+ // indeterminate initial value; if the object or any of its
+ // subobjects are of const-qualified type, the program is
+ // ill-formed.
+ //
+ // This isn't technically an error in C, so we don't diagnose it.
+ //
+ // FIXME: Actually perform the POD/user-defined default
+ // constructor check.
+ if (getLangOptions().CPlusPlus &&
+ Context.getCanonicalType(Type).isConstQualified())
+ Diag(Var->getLocation(),
+ diag::err_const_var_requires_init,
+ Var->getName(),
+ SourceRange(Var->getLocation(), Var->getLocation()));
+ }
+}
+
/// The declarators are chained together backwards, reverse the list.
Sema::DeclTy *Sema::FinalizeDeclaratorGroup(Scope *S, DeclTy *group) {
// Often we have single declarators, handle them quickly.
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Oct 28 19:13:59 2008
@@ -679,3 +679,193 @@
// Set the init expression, handles conversions.
AddInitializerToDecl(Dcl, ExprTys[0]);
}
+
+/// CompareReferenceRelationship - Compare the two types T1 and T2 to
+/// determine whether they are reference-related,
+/// reference-compatible, reference-compatible with added
+/// qualification, or incompatible, for use in C++ initialization by
+/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
+/// type, and the first type (T1) is the pointee type of the reference
+/// type being initialized.
+Sema::ReferenceCompareResult
+Sema::CompareReferenceRelationship(QualType T1, QualType T2) {
+ assert(!T1->isReferenceType() && "T1 must be the pointee type of the reference type");
+ assert(!T2->isReferenceType() && "T2 cannot be a reference type");
+
+ T1 = Context.getCanonicalType(T1);
+ T2 = Context.getCanonicalType(T2);
+ QualType UnqualT1 = T1.getUnqualifiedType();
+ QualType UnqualT2 = T2.getUnqualifiedType();
+
+ // C++ [dcl.init.ref]p4:
+ // Given types âcv1 T1â and âcv2 T2,â âcv1 T1â is
+ // reference-related to âcv2 T2â if T1 is the same type as T2, or
+ // T1 is a base class of T2.
+ //
+ // If neither of these conditions is met, the two types are not
+ // reference related at all.
+ if (UnqualT1 != UnqualT2 && !IsDerivedFrom(UnqualT2, UnqualT1))
+ return Ref_Incompatible;
+
+ // At this point, we know that T1 and T2 are reference-related (at
+ // least).
+
+ // C++ [dcl.init.ref]p4:
+ // "cv1 T1â is reference-compatible with âcv2 T2â if T1 is
+ // reference-related to T2 and cv1 is the same cv-qualification
+ // as, or greater cv-qualification than, cv2. For purposes of
+ // overload resolution, cases for which cv1 is greater
+ // cv-qualification than cv2 are identified as
+ // reference-compatible with added qualification (see 13.3.3.2).
+ if (T1.getCVRQualifiers() == T2.getCVRQualifiers())
+ return Ref_Compatible;
+ else if (T1.isMoreQualifiedThan(T2))
+ return Ref_Compatible_With_Added_Qualification;
+ else
+ return Ref_Related;
+}
+
+/// CheckReferenceInit - Check the initialization of a reference
+/// variable with the given initializer (C++ [dcl.init.ref]). Init is
+/// the initializer (either a simple initializer or an initializer
+/// list), and DeclType is the type of the declaration. When Complain
+/// is true, this routine will produce diagnostics (and return true)
+/// when the declaration cannot be initialized with the given
+/// initializer. When Complain is false, this routine will return true
+/// when the initialization cannot be performed, but will not produce
+/// any diagnostics or alter Init.
+bool Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType, bool Complain) {
+ assert(DeclType->isReferenceType() && "Reference init needs a reference");
+
+ QualType T1 = DeclType->getAsReferenceType()->getPointeeType();
+ QualType T2 = Init->getType();
+
+ Expr::isLvalueResult InitLvalue = Init->isLvalue(Context);
+ ReferenceCompareResult RefRelationship = CompareReferenceRelationship(T1, T2);
+
+ // C++ [dcl.init.ref]p5:
+ // A reference to type âcv1 T1â is initialized by an expression
+ // of type âcv2 T2â as follows:
+
+ // -- If the initializer expression
+
+ bool BindsDirectly = false;
+ // -- is an lvalue (but is not a bit-field), and âcv1 T1â is
+ // reference-compatible with âcv2 T2,â or
+ if (InitLvalue == Expr::LV_Valid && !Init->isBitField() &&
+ RefRelationship >= Ref_Compatible) {
+ BindsDirectly = true;
+
+ if (!Complain) {
+ // FIXME: Binding to a subobject of the lvalue is going to require
+ // more AST annotation than this.
+ ImpCastExprToType(Init, T1);
+ }
+ }
+
+ // -- has a class type (i.e., T2 is a class type) and can be
+ // implicitly converted to an lvalue of type âcv3 T3,â
+ // where âcv1 T1â is reference-compatible with âcv3 T3â
+ // 92) (this conversion is selected by enumerating the
+ // applicable conversion functions (13.3.1.6) and choosing
+ // the best one through overload resolution (13.3)),
+ // FIXME: Implement this second bullet, once we have conversion
+ // functions.
+
+ if (BindsDirectly) {
+ // C++ [dcl.init.ref]p4:
+ // [...] In all cases where the reference-related or
+ // reference-compatible relationship of two types is used to
+ // establish the validity of a reference binding, and T1 is a
+ // base class of T2, a program that necessitates such a binding
+ // is ill-formed if T1 is an inaccessible (clause 11) or
+ // ambiguous (10.2) base class of T2.
+ //
+ // Note that we only check this condition when we're allowed to
+ // complain about errors, because we should not be checking for
+ // ambiguity (or inaccessibility) unless the reference binding
+ // actually happens.
+ if (Complain &&
+ (Context.getCanonicalType(T1).getUnqualifiedType()
+ != Context.getCanonicalType(T2).getUnqualifiedType()) &&
+ CheckDerivedToBaseConversion(T2, T1, Init->getSourceRange().getBegin(),
+ Init->getSourceRange()))
+ return true;
+
+ return false;
+ }
+
+ // -- Otherwise, the reference shall be to a non-volatile const
+ // type (i.e., cv1 shall be const).
+ if (T1.getCVRQualifiers() != QualType::Const) {
+ if (Complain)
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_not_reference_to_const_init,
+ T1.getAsString(),
+ InitLvalue != Expr::LV_Valid? "temporary" : "value",
+ T2.getAsString(), Init->getSourceRange());
+ return true;
+ }
+
+ // -- If the initializer expression is an rvalue, with T2 a
+ // class type, and âcv1 T1â is reference-compatible with
+ // âcv2 T2,â the reference is bound in one of the
+ // following ways (the choice is implementation-defined):
+ //
+ // -- The reference is bound to the object represented by
+ // the rvalue (see 3.10) or to a sub-object within that
+ // object.
+ //
+ // -- A temporary of type âcv1 T2â [sic] is created, and
+ // a constructor is called to copy the entire rvalue
+ // object into the temporary. The reference is bound to
+ // the temporary or to a sub-object within the
+ // temporary.
+ //
+ //
+ // The constructor that would be used to make the copy
+ // shall be callable whether or not the copy is actually
+ // done.
+ //
+ // Note that C++0x [dcl.ref.init]p5 takes away this implementation
+ // freedom, so we will always take the first option and never build
+ // a temporary in this case. FIXME: We will, however, have to check
+ // for the presence of a copy constructor in C++98/03 mode.
+ if (InitLvalue != Expr::LV_Valid && T2->isRecordType() &&
+ RefRelationship >= Ref_Compatible) {
+ if (!Complain) {
+ // FIXME: Binding to a subobject of the rvalue is going to require
+ // more AST annotation than this.
+ ImpCastExprToType(Init, T1);
+ }
+ return false;
+ }
+
+ // -- Otherwise, a temporary of type âcv1 T1â is created and
+ // initialized from the initializer expression using the
+ // rules for a non-reference copy initialization (8.5). The
+ // reference is then bound to the temporary. If T1 is
+ // reference-related to T2, cv1 must be the same
+ // cv-qualification as, or greater cv-qualification than,
+ // cv2; otherwise, the program is ill-formed.
+ if (RefRelationship == Ref_Related) {
+ // If cv1 == cv2 or cv1 is a greater cv-qualified than cv2, then
+ // we would be reference-compatible or reference-compatible with
+ // added qualification. But that wasn't the case, so the reference
+ // initialization fails.
+ if (Complain)
+ Diag(Init->getSourceRange().getBegin(),
+ diag::err_reference_init_drops_quals,
+ T1.getAsString(),
+ InitLvalue != Expr::LV_Valid? "temporary" : "value",
+ T2.getAsString(), Init->getSourceRange());
+ return true;
+ }
+
+ // Actually try to convert the initializer to T1.
+ if (Complain)
+ return PerformImplicitConversion(Init, T1);
+ else
+ return (TryImplicitConversion(Init, T1).ConversionKind
+ == ImplicitConversionSequence::BadConversion);
+}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 28 19:13:59 2008
@@ -1174,14 +1174,11 @@
Arg = new CXXDefaultArgExpr(FDecl->getParamDecl(i));
QualType ArgType = Arg->getType();
- // Compute implicit casts from the operand to the formal argument type.
- AssignConvertType ConvTy =
- CheckSingleAssignmentConstraints(ProtoArgType, Arg);
- TheCall->setArg(i, Arg);
-
- if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), ProtoArgType,
- ArgType, Arg, "passing"))
+ // Pass the argument.
+ if (PerformCopyInitialization(Arg, ProtoArgType, "passing"))
return true;
+
+ TheCall->setArg(i, Arg);
}
// If this is a variadic call, handle args passed through "...".
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Tue Oct 28 19:13:59 2008
@@ -567,7 +567,7 @@
bool
Sema::PerformImplicitConversion(Expr *&From, QualType ToType)
{
- ImplicitConversionSequence ICS = TryCopyInitialization(From, ToType);
+ ImplicitConversionSequence ICS = TryImplicitConversion(From, ToType);
switch (ICS.ConversionKind) {
case ImplicitConversionSequence::StandardConversion:
if (PerformImplicitConversion(From, ToType, ICS.Standard))
Modified: cfe/trunk/lib/Sema/SemaInherit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInherit.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInherit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInherit.cpp Tue Oct 28 19:13:59 2008
@@ -44,33 +44,32 @@
ScratchPath.clear();
}
-/// IsDerivedFrom - Determine whether the class type Derived is
-/// derived from the class type Base, ignoring qualifiers on Base and
-/// Derived. This routine does not assess whether an actual conversion
-/// from a Derived* to a Base* is legal, because it does not account
-/// for ambiguous conversions or conversions to private/protected bases.
+/// IsDerivedFrom - Determine whether the type Derived is derived from
+/// the type Base, ignoring qualifiers on Base and Derived. This
+/// routine does not assess whether an actual conversion from a
+/// Derived* to a Base* is legal, because it does not account for
+/// ambiguous conversions or conversions to private/protected bases.
bool Sema::IsDerivedFrom(QualType Derived, QualType Base) {
BasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false);
return IsDerivedFrom(Derived, Base, Paths);
}
-/// IsDerivedFrom - Determine whether the class type Derived is
-/// derived from the class type Base, ignoring qualifiers on Base and
-/// Derived. This routine does not assess whether an actual conversion
-/// from a Derived* to a Base* is legal, because it does not account
-/// for ambiguous conversions or conversions to private/protected
+/// IsDerivedFrom - Determine whether the type Derived is derived from
+/// the type Base, ignoring qualifiers on Base and Derived. This
+/// routine does not assess whether an actual conversion from a
+/// Derived* to a Base* is legal, because it does not account for
+/// ambiguous conversions or conversions to private/protected
/// bases. This routine will use Paths to determine if there are
/// ambiguous paths (if @c Paths.isFindingAmbiguities()) and record
-/// information about all of the paths (if
-/// @c Paths.isRecordingPaths()).
+/// information about all of the paths (if @c Paths.isRecordingPaths()).
bool Sema::IsDerivedFrom(QualType Derived, QualType Base, BasePaths &Paths) {
bool FoundPath = false;
Derived = Context.getCanonicalType(Derived).getUnqualifiedType();
Base = Context.getCanonicalType(Base).getUnqualifiedType();
- assert(Derived->isRecordType() && "IsDerivedFrom requires a class type");
- assert(Base->isRecordType() && "IsDerivedFrom requires a class type");
+ if (!Derived->isRecordType() || !Base->isRecordType())
+ return false;
if (Derived == Base)
return false;
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 28 19:13:59 2008
@@ -312,11 +312,10 @@
}
}
-/// TryCopyInitialization - Attempt to copy-initialize a value of the
-/// given type (ToType) from the given expression (Expr), as one would
-/// do when copy-initializing a function parameter. This function
-/// returns an implicit conversion sequence that can be used to
-/// perform the initialization. Given
+/// TryImplicitConversion - Attempt to perform an implicit conversion
+/// from the given expression (Expr) to the given type (ToType). This
+/// function returns an implicit conversion sequence that can be used
+/// to perform the initialization. Given
///
/// void f(float f);
/// void g(int i) { f(i); }
@@ -332,7 +331,7 @@
/// but will instead return an implicit conversion sequence of kind
/// "BadConversion".
ImplicitConversionSequence
-Sema::TryCopyInitialization(Expr* From, QualType ToType)
+Sema::TryImplicitConversion(Expr* From, QualType ToType)
{
ImplicitConversionSequence ICS;
@@ -343,32 +342,6 @@
ICS.Standard.Deprecated = false;
ICS.Standard.FromTypePtr = FromType.getAsOpaquePtr();
- if (const ReferenceType *ToTypeRef = ToType->getAsReferenceType()) {
- // FIXME: This is a hack to deal with the initialization of
- // references the way that the C-centric code elsewhere deals with
- // references, by only allowing them if the referred-to type is
- // exactly the same. This means that we're only handling the
- // direct-binding case. The code will be replaced by an
- // implementation of C++ 13.3.3.1.4 once we have the
- // initialization of references implemented.
- QualType ToPointee = Context.getCanonicalType(ToTypeRef->getPointeeType());
-
- // Get down to the canonical type that we're converting from.
- if (const ReferenceType *FromTypeRef = FromType->getAsReferenceType())
- FromType = FromTypeRef->getPointeeType();
- FromType = Context.getCanonicalType(FromType);
-
- ICS.Standard.First = ICK_Identity;
- ICS.Standard.Second = ICK_Identity;
- ICS.Standard.Third = ICK_Identity;
- ICS.Standard.ToTypePtr = ToType.getAsOpaquePtr();
-
- if (FromType != ToPointee)
- ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
-
- return ICS;
- }
-
// The first conversion can be an lvalue-to-rvalue conversion,
// array-to-pointer conversion, or function-to-pointer conversion
// (C++ 4p1).
@@ -482,18 +455,37 @@
ICS.Standard.Second = ICK_Identity;
}
+ QualType CanonFrom;
+ QualType CanonTo;
// The third conversion can be a qualification conversion (C++ 4p1).
if (IsQualificationConversion(FromType, ToType)) {
ICS.Standard.Third = ICK_Qualification;
FromType = ToType;
+ CanonFrom = Context.getCanonicalType(FromType);
+ CanonTo = Context.getCanonicalType(ToType);
} else {
// No conversion required
ICS.Standard.Third = ICK_Identity;
+
+ // C++ [dcl.init]p14 last bullet:
+ // Note: an expression of type "cv1 T" can initialize an object
+ // of type âcv2 Tâ independently of the cv-qualifiers cv1 and
+ // cv2. -- end note]
+ //
+ // FIXME: Where is the normative text?
+ CanonFrom = Context.getCanonicalType(FromType);
+ CanonTo = Context.getCanonicalType(ToType);
+ if (!FromType->isRecordType() &&
+ CanonFrom.getUnqualifiedType() == CanonTo.getUnqualifiedType() &&
+ CanonFrom.getCVRQualifiers() != CanonTo.getCVRQualifiers()) {
+ FromType = ToType;
+ CanonFrom = CanonTo;
+ }
}
// If we have not converted the argument type to the parameter type,
// this is a bad conversion sequence.
- if (Context.getCanonicalType(FromType) != Context.getCanonicalType(ToType))
+ if (CanonFrom != CanonTo)
ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
ICS.Standard.ToTypePtr = FromType.getAsOpaquePtr();
@@ -1054,6 +1046,63 @@
return ImplicitConversionSequence::Indistinguishable;
}
+/// TryCopyInitialization - Try to copy-initialize a value of type
+/// ToType from the expression From. Return the implicit conversion
+/// sequence required to pass this argument, which may be a bad
+/// conversion sequence (meaning that the argument cannot be passed to
+/// a parameter of this type). This is user for argument passing,
+ImplicitConversionSequence
+Sema::TryCopyInitialization(Expr *From, QualType ToType) {
+ if (!getLangOptions().CPlusPlus) {
+ // In C, argument passing is the same as performing an assignment.
+ AssignConvertType ConvTy =
+ CheckSingleAssignmentConstraints(ToType, From);
+ ImplicitConversionSequence ICS;
+ if (getLangOptions().NoExtensions? ConvTy != Compatible
+ : ConvTy == Incompatible)
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ else
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ return ICS;
+ } else if (ToType->isReferenceType()) {
+ ImplicitConversionSequence ICS;
+ if (CheckReferenceInit(From, ToType, /*Complain=*/false))
+ ICS.ConversionKind = ImplicitConversionSequence::BadConversion;
+ else
+ ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
+ return ICS;
+ } else {
+ return TryImplicitConversion(From, ToType);
+ }
+}
+
+/// PerformArgumentPassing - Pass the argument Arg into a parameter of
+/// type ToType. Returns true (and emits a diagnostic) if there was
+/// an error, returns false if the initialization succeeded.
+bool Sema::PerformCopyInitialization(Expr *&From, QualType ToType,
+ const char* Flavor) {
+ if (!getLangOptions().CPlusPlus) {
+ // In C, argument passing is the same as performing an assignment.
+ QualType FromType = From->getType();
+ AssignConvertType ConvTy =
+ CheckSingleAssignmentConstraints(ToType, From);
+
+ return DiagnoseAssignmentResult(ConvTy, From->getLocStart(), ToType,
+ FromType, From, Flavor);
+ } else if (ToType->isReferenceType()) {
+ return CheckReferenceInit(From, ToType);
+ } else {
+ if (PerformImplicitConversion(From, ToType))
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_convert_incompatible,
+ ToType.getAsString(), From->getType().getAsString(),
+ Flavor,
+ From->getSourceRange());
+ else
+ return false;
+ }
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments.
void
Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Oct 28 19:13:59 2008
@@ -693,7 +693,7 @@
return new BreakStmt(BreakLoc);
}
-/// ActOnBlockReturnStmt - Utilty routine to figure out block's return type.
+/// ActOnBlockReturnStmt - Utility routine to figure out block's return type.
///
Action::StmtResult
Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
@@ -782,10 +782,11 @@
// C99 6.8.6.4p3(136): The return statement is not an assignment. The
// overlap restriction of subclause 6.5.16.1 does not apply to the case of
// function return.
- AssignConvertType ConvTy = CheckSingleAssignmentConstraints(FnRetType,
- RetValExp);
- if (DiagnoseAssignmentResult(ConvTy, ReturnLoc, FnRetType,
- RetValType, RetValExp, "returning"))
+
+ // In C++ the return statement is handled via a copy initialization.
+ // the C version of which boils down to
+ // CheckSingleAssignmentConstraints.
+ if (PerformCopyInitialization(RetValExp, FnRetType, "returning"))
return true;
if (RetValExp) CheckReturnStackAddr(RetValExp, FnRetType, ReturnLoc);
Modified: cfe/trunk/test/Parser/cxx-reference.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-reference.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx-reference.cpp (original)
+++ cfe/trunk/test/Parser/cxx-reference.cpp Tue Oct 28 19:13:59 2008
@@ -3,6 +3,8 @@
extern char *bork;
char *& bar = bork;
+int val;
+
void foo(int &a) {
}
@@ -11,7 +13,7 @@
void g(const A aref) {
}
-int & const X; // expected-error {{'const' qualifier may not be applied to a reference}}
-int & volatile Y; // expected-error {{'volatile' qualifier may not be applied to a reference}}
-int & const volatile Z; /* expected-error {{'const' qualifier may not be applied}} \
+int & const X = val; // expected-error {{'const' qualifier may not be applied to a reference}}
+int & volatile Y = val; // expected-error {{'volatile' qualifier may not be applied to a reference}}
+int & const volatile Z = val; /* expected-error {{'const' qualifier may not be applied}} \
expected-error {{'volatile' qualifier may not be applied}} */
Modified: cfe/trunk/test/SemaCXX/overload-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overload-call.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/overload-call.cpp (original)
+++ cfe/trunk/test/SemaCXX/overload-call.cpp Tue Oct 28 19:13:59 2008
@@ -214,3 +214,14 @@
char* d8 = derived3(d);
}
+
+// Test overloading of references.
+// (FIXME: tests binding to determine candidate sets, not overload
+// resolution per se).
+int* intref(int&);
+float* intref(const int&);
+
+void intref_test() {
+ float* ir1 = intref(5);
+ float* ir2 = intref(5.5);
+}
Modified: cfe/trunk/test/SemaCXX/references.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/references.cpp?rev=58353&r1=58352&r2=58353&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/references.cpp (original)
+++ cfe/trunk/test/SemaCXX/references.cpp Tue Oct 28 19:13:59 2008
@@ -1,4 +1,4 @@
-// RUN: clang -fsyntax-only %s
+// RUN: clang -fsyntax-only -verify %s
int g(int);
void f() {
@@ -7,10 +7,10 @@
r = 1;
int *p = &r;
int &rr = r;
- int (&rg)(int) = g;
+ int (&rg)(int) = g; // expected-warning{{statement was disambiguated as declaration}}
rg(i);
int a[3];
- int (&ra)[3] = a;
+ int (&ra)[3] = a; // expected-warning{{statement was disambiguated as declaration}}
ra[1] = i;
int *Q;
int *& P = Q;
@@ -24,5 +24,57 @@
int c[3];
- int (&rc)[3] = c;
+ int (&rc)[3] = c; // expected-warning{{statement was disambiguated as declaration}}
+}
+
+// C++ [dcl.init.ref]p5b1
+struct A { };
+struct B : A { } b;
+
+void test3() {
+ double d = 2.0;
+ double& rd = d; // rd refers to d
+ const double& rcd = d; // rcd refers to d
+
+ A& ra = b; // ra refers to A subobject in b
+ const A& rca = b; // rca refers to A subobject in b
+}
+
+B fB();
+
+// C++ [dcl.init.ref]p5b2
+void test4() {
+ double& rd2 = 2.0; // expected-error{{non-const reference to type 'double' cannot be initialized with a temporary of type 'double'}}
+ int i = 2;
+ double& rd3 = i; // expected-error{{non-const reference to type 'double' cannot be initialized with a value of type 'int'}}
+
+ const A& rca = fB();
+}
+
+void test5() {
+ const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0
+ const volatile int cvi = 1;
+ const int& r = cvi; // expected-error{{initialization of reference to type 'int const' with a value of type 'int const volatile' drops qualifiers}}
+}
+
+// C++ [dcl.init.ref]p3
+int& test6(int& x) {
+ int& yo; // expected-error{{declaration of reference variable 'yo' requires an initializer}}
+
+
+ const int val; // expected-error{{declaration of const variable 'val' requires an initializer}}
+
+ return x;
+}
+int& not_initialized_error; // expected-error{{declaration of reference variable 'not_initialized_error' requires an initializer}}
+extern int& not_initialized_okay;
+
+class Test6 {
+ int& okay;
+};
+
+struct C : B, A { };
+
+void test7(C& c) {
+ A& a1 = c; // expected-error {{ambiguous conversion from derived class 'struct C' to base class 'struct A':}}
}
More information about the cfe-commits
mailing list