[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