[cfe-commits] r49078 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaType.cpp test/CodeGen/address-space.c test/Sema/typedef-retain.c

Chris Lattner sabre at nondot.org
Tue Apr 1 22:18:44 PDT 2008


Author: lattner
Date: Wed Apr  2 00:18:44 2008
New Revision: 49078

URL: http://llvm.org/viewvc/llvm-project?rev=49078&view=rev
Log:
Fix several bugs in array -> pointer decomposition.

First, we got several CVR propagation cases wrong, which Eli pointed
out in PR2039.

Second, we didn't propagate address space qualifiers correctly, leading
to incorrect lowering of code in CodeGen/address-space.c.

Third, we didn't uniformly propagate the specifier in the array to the
pointer ("int[restrict 4]" -> "int *restrict").

This adds an ASTContext::getArrayDecayedType member that handles the 
non-trivial logic for this seemingly simple operation.


Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CodeGen/address-space.c
    cfe/trunk/test/Sema/typedef-retain.c

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

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Apr  2 00:18:44 2008
@@ -287,6 +287,14 @@
   //                            Type Operators
   //===--------------------------------------------------------------------===//
   
+  /// getArrayDecayedType - Return the properly qualified result of decaying the
+  /// specified array type to a pointer.  This operation is non-trivial when
+  /// handling typedefs etc.  The canonical type of "T" must be an array type,
+  /// this returns a pointer to a properly qualified element of the array.
+  ///
+  /// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
+  QualType getArrayDecayedType(QualType T);
+  
   /// maxIntegerType - Returns the highest ranked integer type. Handles 3
   /// different type combos: unsigned/unsigned, signed/signed, signed/unsigned.
   static QualType maxIntegerType(QualType lhs, QualType rhs);

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

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Apr  2 00:18:44 2008
@@ -929,6 +929,71 @@
   return IntTy; 
 }
 
+//===----------------------------------------------------------------------===//
+//                              Type Operators
+//===----------------------------------------------------------------------===//
+
+/// getArrayDecayedType - Return the properly qualified result of decaying the
+/// specified array type to a pointer.  This operation is non-trivial when
+/// handling typedefs etc.  The canonical type of "T" must be an array type,
+/// this returns a pointer to a properly qualified element of the array.
+///
+/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
+QualType ASTContext::getArrayDecayedType(QualType Ty) {
+  // Handle the common case where typedefs are not involved directly.
+  QualType EltTy;
+  unsigned ArrayQuals = 0;
+  unsigned PointerQuals = 0;
+  if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) {
+    // Since T "isa" an array type, it could not have had an address space
+    // qualifier, just CVR qualifiers.  The properly qualified element pointer
+    // gets the union of the CVR qualifiers from the element and the array, and
+    // keeps any address space qualifier on the element type if present.
+    EltTy = AT->getElementType();
+    ArrayQuals = Ty.getCVRQualifiers();
+    PointerQuals = AT->getIndexTypeQualifier();
+  } else {
+    // Otherwise, we have an ASQualType or a typedef, etc.  Make sure we don't
+    // lose qualifiers when dealing with typedefs. Example:
+    //   typedef int arr[10];
+    //   void test2() {
+    //     const arr b;
+    //     b[4] = 1;
+    //   }
+    //
+    // The decayed type of b is "const int*" even though the element type of the
+    // array is "int".
+    QualType CanTy = Ty.getCanonicalType();
+    const ArrayType *PrettyArrayType = Ty->getAsArrayType();
+    assert(PrettyArrayType && "Not an array type!");
+    
+    // Get the element type with 'getAsArrayType' so that we don't lose any
+    // typedefs in the element type of the array.
+    EltTy = PrettyArrayType->getElementType();
+
+    // If the array was address-space qualifier, make sure to ASQual the element
+    // type.  We can just grab the address space from the canonical type.
+    if (unsigned AS = CanTy.getAddressSpace())
+      EltTy = getASQualType(EltTy, AS);
+    
+    // To properly handle [multiple levels of] typedefs, typeof's etc, we take
+    // the CVR qualifiers directly from the canonical type, which is guaranteed
+    // to have the full set unioned together.
+    ArrayQuals = CanTy.getCVRQualifiers();
+    PointerQuals = PrettyArrayType->getIndexTypeQualifier();
+  }
+  
+  // Apply any CVR qualifiers from the array type.
+  EltTy = EltTy.getQualifiedType(ArrayQuals | EltTy.getCVRQualifiers());
+
+  QualType PtrTy = getPointerType(EltTy);
+
+  // int x[restrict 4] ->  int *restrict
+  PtrTy = PtrTy.getQualifiedType(PointerQuals);
+
+  return PtrTy;
+}
+
 /// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
 /// routine will assert if passed a built-in type that isn't an integer or enum.
 static int getIntegerRank(QualType t) {

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Apr  2 00:18:44 2008
@@ -1014,10 +1014,9 @@
   // we need to consider storing both types (in ParmVarDecl)...
   // 
   QualType parmDeclType = QualType::getFromOpaquePtr(PI.TypeInfo);
-  if (const ArrayType *AT = parmDeclType->getAsArrayType()) {
+  if (parmDeclType->isArrayType()) {
     // int x[restrict 4] ->  int *restrict
-    parmDeclType = Context.getPointerType(AT->getElementType());
-    parmDeclType = parmDeclType.getQualifiedType(AT->getIndexTypeQualifier());
+    parmDeclType = Context.getArrayDecayedType(parmDeclType);
   } else if (parmDeclType->isFunctionType())
     parmDeclType = Context.getPointerType(parmDeclType);
   

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Apr  2 00:18:44 2008
@@ -932,18 +932,8 @@
   }
   if (Ty->isFunctionType())
     ImpCastExprToType(E, Context.getPointerType(Ty));
-  else if (const ArrayType *ArrayTy = Ty->getAsArrayType()) {
-    // Make sure we don't lose qualifiers when dealing with typedefs. Example:
-    //   typedef int arr[10];
-    //   void test2() {
-    //     const arr b;
-    //     b[4] = 1;
-    //   }
-    QualType ELT = ArrayTy->getElementType();
-    // FIXME: Handle ASQualType
-    ELT = ELT.getQualifiedType(Ty.getCVRQualifiers()|ELT.getCVRQualifiers());
-    ImpCastExprToType(E, Context.getPointerType(ELT));
-  }
+  else if (Ty->isArrayType())
+    ImpCastExprToType(E, Context.getArrayDecayedType(Ty));
 }
 
 /// UsualUnaryConversions - Performs various conversions that are common to most

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Apr  2 00:18:44 2008
@@ -317,18 +317,17 @@
           // type in ParmVarDecl (which makes the code generator unhappy).
           //
           // FIXME: We still apparently need the conversion in 
-          // Sema::ParseParamDeclarator(). This doesn't make any sense, since
+          // Sema::ActOnParamDeclarator(). This doesn't make any sense, since
           // it should be driving off the type being created here.
           // 
           // FIXME: If a source translation tool needs to see the original type,
           // then we need to consider storing both types somewhere...
           // 
-          if (const ArrayType *AT = ArgTy->getAsArrayType()) {
-            // int x[restrict 4] ->  int *restrict
-            ArgTy = Context.getPointerType(AT->getElementType());
-            ArgTy = ArgTy.getQualifiedType(AT->getIndexTypeQualifier());
+          if (ArgTy->isArrayType()) {
+            ArgTy = Context.getArrayDecayedType(ArgTy);
           } else if (ArgTy->isFunctionType())
             ArgTy = Context.getPointerType(ArgTy);
+          
           // Look for 'void'.  void is allowed only as a single argument to a
           // function with no other parameters (C99 6.7.5.3p10).  We record
           // int(void) as a FunctionTypeProto with an empty argument list.
@@ -391,9 +390,9 @@
     assert(!ArgTy.isNull() && "Couldn't parse type?");
     // Perform the default function/array conversion (C99 6.7.5.3p[7,8]).
     // This matches the conversion that is done in 
-    // Sema::ParseParamDeclarator(). 
-    if (const ArrayType *AT = ArgTy->getAsArrayType())
-      ArgTy = Context.getPointerType(AT->getElementType());
+    // Sema::ActOnParamDeclarator(). 
+    if (ArgTy->isArrayType())
+      ArgTy = Context.getArrayDecayedType(ArgTy);
     else if (ArgTy->isFunctionType())
       ArgTy = Context.getPointerType(ArgTy);
     ArgTys.push_back(ArgTy);

Modified: cfe/trunk/test/CodeGen/address-space.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/address-space.c?rev=49078&r1=49077&r2=49078&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/address-space.c (original)
+++ cfe/trunk/test/CodeGen/address-space.c Wed Apr  2 00:18:44 2008
@@ -1,4 +1,4 @@
-// RUN: clang -emit-llvm < %s 2>&1 | grep 'addrspace(1)' | count 5
+// RUN: clang -emit-llvm < %s 2>&1 | grep 'addrspace(1)' | count 6
 int foo __attribute__((address_space(1)));
 int ban[10] __attribute__((address_space(1)));
 

Modified: cfe/trunk/test/Sema/typedef-retain.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/typedef-retain.c?rev=49078&r1=49077&r2=49078&view=diff

==============================================================================
--- cfe/trunk/test/Sema/typedef-retain.c (original)
+++ cfe/trunk/test/Sema/typedef-retain.c Wed Apr  2 00:18:44 2008
@@ -12,3 +12,15 @@
     result[i] = a; // expected-error {{assigning 'float4', expected 'int4'}}
 }
 
+// PR2039
+typedef int a[5];
+void z() {
+  typedef const a b;
+  b r;
+  r[0]=10;  // expected-error {{read-only variable is not assignable}}
+}
+
+int e(const a y) {
+  y[0] = 10; // expected-error {{read-only variable is not assignable}}
+}
+





More information about the cfe-commits mailing list