[cfe-commits] r57935 - in /cfe/trunk: include/clang/AST/Type.h lib/AST/Expr.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaType.cpp test/SemaCXX/decl-expr-ambiguity.cpp test/SemaCXX/qualification-conversion.cpp

Douglas Gregor doug.gregor at gmail.com
Tue Oct 21 16:43:53 PDT 2008


Author: dgregor
Date: Tue Oct 21 18:43:52 2008
New Revision: 57935

URL: http://llvm.org/viewvc/llvm-project?rev=57935&view=rev
Log:
Initial step toward supporting qualification conversions (C++ 4.4).

Changes:
  - Sema::IsQualificationConversion determines whether we have a qualification
    conversion.
  - Sema::CheckSingleAssignment constraints now follows the C++ rules in C++,
    performing an implicit conversion from the right-hand side to the type of
    the left-hand side rather than checking based on the C notion of 
    "compatibility". We now rely on the implicit-conversion code to
    determine whether the conversion can happen or
    not. Sema::TryCopyInitialization has an ugly reference-related
    hack to cope with the initialization of references, for now.
  - When building DeclRefExprs, strip away the reference type, since
    there are no expressions whose type is a reference. We'll need to
    do this throughout Sema.
  - Expr::isLvalue now permits functions to be lvalues in C++ (but not
  in C).


Added:
    cfe/trunk/test/SemaCXX/qualification-conversion.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Tue Oct 21 18:43:52 2008
@@ -160,6 +160,27 @@
   
   inline QualType getUnqualifiedType() const;
   
+  /// isMoreQualifiedThan - Determine whether this type is more
+  /// qualified than the Other type. For example, "const volatile int"
+  /// is more qualified than "const int", "volatile int", and
+  /// "int". However, it is not more qualified than "const volatile
+  /// int".
+  bool isMoreQualifiedThan(QualType Other) const {
+    unsigned MyQuals = this->getCVRQualifiers();
+    unsigned OtherQuals = Other.getCVRQualifiers();
+    return MyQuals != OtherQuals && (MyQuals | OtherQuals) == MyQuals;
+  }
+
+  /// isAtLeastAsQualifiedAs - Determine whether this type is at last
+  /// as qualified as the Other type. For example, "const volatile
+  /// int" is at least as qualified as "const int", "volatile int",
+  /// "int", and "const volatile int".
+  bool isAtLeastAsQualifiedAs(QualType Other) const {
+    unsigned MyQuals = this->getCVRQualifiers();
+    unsigned OtherQuals = Other.getCVRQualifiers();
+    return MyQuals | OtherQuals == MyQuals;
+  }
+
   /// operator==/!= - Indicate whether the specified types and qualifiers are
   /// identical.
   bool operator==(const QualType &RHS) const {

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Tue Oct 21 18:43:52 2008
@@ -15,6 +15,7 @@
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/RecordLayout.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/Basic/TargetInfo.h"
@@ -334,14 +335,17 @@
 ///  - reference type [C++ [expr]]
 ///
 Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
-  // first, check the type (C99 6.3.2.1)
-  if (TR->isFunctionType()) // from isObjectType()
+  // first, check the type (C99 6.3.2.1). Expressions with function
+  // type in C are not lvalues, but they can be lvalues in C++.
+  if (!Ctx.getLangOptions().CPlusPlus && TR->isFunctionType())
     return LV_NotObjectType;
 
   // Allow qualified void which is an incomplete type other than void (yuck).
   if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
     return LV_IncompleteVoidType;
 
+  /// FIXME: Expressions can't have reference type, so the following
+  /// isn't needed.
   if (TR->isReferenceType()) // C++ [expr]
     return LV_Valid;
 
@@ -356,7 +360,11 @@
     return LV_Valid;
   case DeclRefExprClass: { // C99 6.5.1p2
     const Decl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
-    if (isa<VarDecl>(RefdDecl) || isa<ImplicitParamDecl>(RefdDecl))
+    if (isa<VarDecl>(RefdDecl) || 
+        isa<ImplicitParamDecl>(RefdDecl) ||
+        // C++ 3.10p2: An lvalue refers to an object or function.
+        isa<FunctionDecl>(RefdDecl) || 
+        isa<OverloadedFunctionDecl>(RefdDecl))
       return LV_Valid;
     break;
   }

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Oct 21 18:43:52 2008
@@ -259,7 +259,7 @@
   QualType ConvertDeclSpecToType(const DeclSpec &DS);
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
   QualType GetTypeForDeclarator(Declarator &D, Scope *S);
-
+  QualType GetNonReferenceType(QualType Type);
   
   QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
 
@@ -371,6 +371,7 @@
   bool IsFloatingPointPromotion(QualType FromType, QualType ToType);
   bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
                            QualType& ConvertedType);
+  bool IsQualificationConversion(QualType FromType, QualType ToType);
 
   ImplicitConversionSequence::CompareKind 
   CompareImplicitConversionSequences(const ImplicitConversionSequence& ICS1,

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 21 18:43:52 2008
@@ -450,7 +450,7 @@
   }
   // If this reference is not in a block or if the referenced variable is
   // within the block, create a normal DeclRefExpr.
-  return new DeclRefExpr(VD, VD->getType(), Loc);
+  return new DeclRefExpr(VD, GetNonReferenceType(VD->getType()), Loc);
 }
 
 Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1565,8 +1565,7 @@
   // 3 & 4 (below). ...and the type *pointed to* by the left has all the 
   // qualifiers of the type *pointed to* by the right; 
   // FIXME: Handle ASQualType
-  if ((lhptee.getCVRQualifiers() & rhptee.getCVRQualifiers()) != 
-       rhptee.getCVRQualifiers())
+  if (!lhptee.isAtLeastAsQualifiedAs(rhptee))
     ConvTy = CompatiblePointerDiscardsQualifiers;
 
   // C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or 
@@ -1766,6 +1765,28 @@
 
 Sema::AssignConvertType
 Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
+  if (getLangOptions().CPlusPlus) {
+    if (!lhsType->isRecordType()) {
+      // C++ 5.17p3: If the left operand is not of class type, the
+      // expression is implicitly converted (C++ 4) to the
+      // cv-unqualified type of the left operand.
+      ImplicitConversionSequence ICS 
+        = TryCopyInitialization(rExpr, lhsType.getUnqualifiedType());
+      if (ICS.ConversionKind == ImplicitConversionSequence::BadConversion) {
+        // No implicit conversion available; we cannot perform this
+        // assignment.
+        return Incompatible;
+      } else {
+        // Perform the appropriate cast to the right-handle side.
+        ImpCastExprToType(rExpr, lhsType.getUnqualifiedType());
+        return Compatible;
+      }
+    }
+
+    // FIXME: Currently, we fall through and treat C++ classes like C
+    // structures.
+  }
+
   // C99 6.5.16.1p1: the left operand is a pointer and the right is
   // a null pointer constant.
   if ((lhsType->isPointerType() || lhsType->isObjCQualifiedIdType() ||

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Oct 21 18:43:52 2008
@@ -318,6 +318,32 @@
   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).
@@ -432,10 +458,7 @@
   }
 
   // The third conversion can be a qualification conversion (C++ 4p1).
-  // FIXME: CheckPointerTypesForAssignment isn't the right way to
-  // determine whether we have a qualification conversion.
-  if (Context.getCanonicalType(FromType) != Context.getCanonicalType(ToType)
-      && CheckPointerTypesForAssignment(ToType, FromType) == Compatible) {
+  if (IsQualificationConversion(FromType, ToType)) {
     ICS.Standard.Third = ICK_Qualification;
     FromType = ToType;
   } else {
@@ -618,6 +641,74 @@
   return false;
 }
 
+/// IsQualificationConversion - Determines whether the conversion from
+/// an rvalue of type FromType to ToType is a qualification conversion
+/// (C++ 4.4).
+bool 
+Sema::IsQualificationConversion(QualType FromType, QualType ToType)
+{
+  FromType = Context.getCanonicalType(FromType);
+  ToType = Context.getCanonicalType(ToType);
+
+  // If FromType and ToType are the same type, this is not a
+  // qualification conversion.
+  if (FromType == ToType)
+    return false;
+    
+  // (C++ 4.4p4):
+  //   A conversion can add cv-qualifiers at levels other than the first
+  //   in multi-level pointers, subject to the following rules: [...]
+  bool PreviousToQualsIncludeConst = true;
+  bool UnwrappedPointer;
+  bool UnwrappedAnyPointer = false;
+  do {
+    // Within each iteration of the loop, we check the qualifiers to
+    // determine if this still looks like a qualification
+    // conversion. Then, if all is well, we unwrap one more level of
+    // pointers (FIXME: or pointers-to-members) and do it all again
+    // until there are no more pointers or pointers-to-members left to
+    // unwrap.
+    UnwrappedPointer = false;
+
+    //   -- the pointer types are similar.
+    const PointerType *FromPtrType = FromType->getAsPointerType(),
+                      *ToPtrType   = ToType->getAsPointerType();
+    if (FromPtrType && ToPtrType) {
+      // The pointer types appear similar. Look at their pointee types.
+      FromType = FromPtrType->getPointeeType();
+      ToType = ToPtrType->getPointeeType();
+      UnwrappedPointer = true;
+      UnwrappedAnyPointer = true;
+    } 
+
+    // FIXME: Cope with pointer-to-member types.
+
+    //   -- for every j > 0, if const is in cv 1,j then const is in cv
+    //      2,j, and similarly for volatile.
+    if (FromType.isMoreQualifiedThan(ToType))
+      return false;
+
+    //   -- if the cv 1,j and cv 2,j are different, then const is in
+    //      every cv for 0 < k < j.
+    if (FromType.getCVRQualifiers() != ToType.getCVRQualifiers()
+	&& !PreviousToQualsIncludeConst)
+      return false;
+
+    // Keep track of whether all prior cv-qualifiers in the "to" type
+    // include const.
+    PreviousToQualsIncludeConst 
+      = PreviousToQualsIncludeConst && ToType.isConstQualified();
+  } while (UnwrappedPointer);
+
+  // We are left with FromType and ToType being the pointee types
+  // after unwrapping the original FromType and ToType the same number
+  // of types. If we unwrapped any pointers, and if FromType and
+  // ToType have the same unqualified type (since we checked
+  // qualifiers above), then this is a qualification conversion.
+  return UnwrappedAnyPointer &&
+    FromType.getUnqualifiedType() == ToType.getUnqualifiedType();
+}
+
 /// CompareImplicitConversionSequences - Compare two implicit
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2).

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Oct 21 18:43:52 2008
@@ -500,6 +500,23 @@
   return T;
 }
 
+/// GetNonReferenceType - If Type is a reference type (e.g., const
+/// int&), returns the type that the reference refers to ("const
+/// int"). Otherwise, returns the type itself. This routine is used
+/// throughout to implement C++ 5p6:
+///
+///   If an expression initially has the type "reference to T" (8.3.2,
+///   8.5.3), the type is adjusted to "T" prior to any further
+///   analysis, the expression designates the object or function
+///   denoted by the reference, and the expression is an lvalue.
+QualType Sema::GetNonReferenceType(QualType Type)
+{
+  if (const ReferenceType *RefType = Type->getAsReferenceType())
+    return RefType->getPointeeType();
+  else
+    return Type;
+}
+
 /// ObjCGetTypeForMethodDefinition - Builds the type for a method definition
 /// declarator
 QualType Sema::ObjCGetTypeForMethodDefinition(DeclTy *D) {

Modified: cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp?rev=57935&r1=57934&r2=57935&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp (original)
+++ cfe/trunk/test/SemaCXX/decl-expr-ambiguity.cpp Tue Oct 21 18:43:52 2008
@@ -38,6 +38,6 @@
 int g(C);
 
 void foo() {
-  fn(1); // expected-error {{incompatible integer to pointer conversion passing 'int', expected 'int (*)(class C)'}}
+  fn(1); // expected-error {{incompatible type passing 'int', expected 'int (*)(class C)'}}
   fn(g); // OK
 }

Added: cfe/trunk/test/SemaCXX/qualification-conversion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualification-conversion.cpp?rev=57935&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/qualification-conversion.cpp (added)
+++ cfe/trunk/test/SemaCXX/qualification-conversion.cpp Tue Oct 21 18:43:52 2008
@@ -0,0 +1,11 @@
+// RUN: clang -fsyntax-only -pedantic -verify %s 
+int* quals1(int const * p);
+int* quals2(int const * const * pp);
+int* quals3(int const * * const * ppp);
+
+void test_quals(int * p, int * * pp, int * * * ppp) {
+  int const * const * pp2 = pp; 
+  quals1(p);
+  quals2(pp);
+  quals3(ppp); // expected-error {{ incompatible type passing 'int ***', expected 'int const **const *' }}
+}





More information about the cfe-commits mailing list