[cfe-commits] r132172 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaType.cpp test/CodeGenCXX/template-instantiation.cpp test/SemaTemplate/instantiate-init.cpp

Chandler Carruth chandlerc at gmail.com
Thu May 26 18:33:31 PDT 2011


Author: chandlerc
Date: Thu May 26 20:33:31 2011
New Revision: 132172

URL: http://llvm.org/viewvc/llvm-project?rev=132172&view=rev
Log:
Enhance Clang to start instantiating static data member definitions
within class templates when they are necessary to complete the type of
the member. The canonical example is code like:

  template <typename T> struct S {
    static const int arr[];
    static const int x;
    static int f();
  };

  template <typename T> const int S<T>::arr[] = { 1, 2, 3 };
  template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]);
  template <typename T> int S<T>::f() { return x; }

  int x = S<int>::f();

We need to instantiate S<T>::arr's definition to pick up its initializer
and complete the array type. This involves new code to specially handle
completing the type of an expression where the type alone is
insufficient. It also requires *updating* the expression with the newly
completed type. Fortunately, all the other infrastructure is already in
Clang to do the instantiation, do the completion, and prune out the
unused bits of code that result from this instantiation.

This addresses the initial bug in PR10001, and will be a step to
fleshing out other cases where we need to work harder to complete an
expression's type. Who knew we still had missing C++03 "features"?

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CodeGenCXX/template-instantiation.cpp
    cfe/trunk/test/SemaTemplate/instantiate-init.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=132172&r1=132171&r2=132172&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu May 26 20:33:31 2011
@@ -808,6 +808,10 @@
                            const PartialDiagnostic &PD);
   bool RequireCompleteType(SourceLocation Loc, QualType T,
                            unsigned DiagID);
+  bool RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
+                               std::pair<SourceLocation,
+                                         PartialDiagnostic> Note);
+
 
   QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
                              const CXXScopeSpec &SS, QualType T);

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=132172&r1=132171&r2=132172&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu May 26 20:33:31 2011
@@ -3111,14 +3111,46 @@
 /// \brief Check the constrains on expression operands to unary type expression
 /// and type traits.
 ///
-/// This is just a convenience wrapper around
-/// Sema::CheckUnaryExprOrTypeTraitOperand.
+/// Completes any types necessary and validates the constraints on the operand
+/// expression. The logic mostly mirrors the type-based overload, but may modify
+/// the expression as it completes the type for that expression through template
+/// instantiation, etc.
 bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *Op,
                                             UnaryExprOrTypeTrait ExprKind) {
-  return CheckUnaryExprOrTypeTraitOperand(Op->getType(),
-                                          Op->getExprLoc(),
-                                          Op->getSourceRange(),
-                                          ExprKind);
+  QualType ExprTy = Op->getType();
+
+  // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+  //   the result is the size of the referenced type."
+  // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+  //   result shall be the alignment of the referenced type."
+  if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+    ExprTy = Ref->getPointeeType();
+
+  if (ExprKind == UETT_VecStep)
+    return CheckVecStepTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+                                        Op->getSourceRange());
+
+  // Whitelist some types as extensions
+  if (!CheckExtensionTraitOperandType(*this, ExprTy, Op->getExprLoc(),
+                                      Op->getSourceRange(), ExprKind))
+    return false;
+
+  if (RequireCompleteExprType(Op,
+                              PDiag(diag::err_sizeof_alignof_incomplete_type)
+                              << ExprKind << Op->getSourceRange(),
+                              std::make_pair(SourceLocation(), PDiag(0))))
+    return true;
+
+  // Completeing the expression's type may have changed it.
+  ExprTy = Op->getType();
+  if (const ReferenceType *Ref = ExprTy->getAs<ReferenceType>())
+    ExprTy = Ref->getPointeeType();
+
+  if (CheckObjCTraitOperandConstraints(*this, ExprTy, Op->getExprLoc(),
+                                       Op->getSourceRange(), ExprKind))
+    return true;
+
+  return false;
 }
 
 /// \brief Check the constraints on operands to unary expression and type

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=132172&r1=132171&r2=132172&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Thu May 26 20:33:31 2011
@@ -3246,6 +3246,61 @@
   } while ((attrs = next));
 }
 
+/// \brief Ensure that the type of the given expression is complete.
+///
+/// This routine checks whether the expression \p E has a complete type. If the
+/// expression refers to an instantiable construct, that instantiation is
+/// performed as needed to complete its type. Furthermore
+/// Sema::RequireCompleteType is called for the expression's type (or in the
+/// case of a reference type, the referred-to type).
+///
+/// \param E The expression whose type is required to be complete.
+/// \param PD The partial diagnostic that will be printed out if the type cannot
+/// be completed.
+///
+/// \returns \c true if the type of \p E is incomplete and diagnosed, \c false
+/// otherwise.
+bool Sema::RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD,
+                                   std::pair<SourceLocation,
+                                             PartialDiagnostic> Note) {
+  QualType T = E->getType();
+
+  // Fast path the case where the type is already complete.
+  if (!T->isIncompleteType())
+    return false;
+
+  // Incomplete array types may be completed by the initializer attached to
+  // their definitions. For static data members of class templates we need to
+  // instantiate the definition to get this initializer and complete the type.
+  if (T->isIncompleteArrayType()) {
+    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+      if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+        if (Var->isStaticDataMember() &&
+            Var->getInstantiatedFromStaticDataMember()) {
+          InstantiateStaticDataMemberDefinition(E->getExprLoc(), Var);
+          // Update the type to the newly instantiated definition's type both
+          // here and within the expression.
+          T = Var->getDefinition()->getType();
+          E->setType(T);
+
+          // We still go on to try to complete the type independently, as it
+          // may also require instantiations or diagnostics if it remains
+          // incomplete.
+        }
+      }
+    }
+  }
+
+  // FIXME: Are there other cases which require instantiating something other
+  // than the type to complete the type of an expression?
+
+  // Look through reference types and complete the referred type.
+  if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+    T = Ref->getPointeeType();
+
+  return RequireCompleteType(E->getExprLoc(), T, PD, Note);
+}
+
 /// @brief Ensure that the type T is a complete type.
 ///
 /// This routine checks whether the type @p T is complete in any

Modified: cfe/trunk/test/CodeGenCXX/template-instantiation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/template-instantiation.cpp?rev=132172&r1=132171&r2=132172&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/template-instantiation.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/template-instantiation.cpp Thu May 26 20:33:31 2011
@@ -1,9 +1,15 @@
 // RUN: %clang_cc1 %s -O1 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
 
+// CHECK: @_ZN7PR100011xE = global
+// CHECK-NOT: @_ZN7PR100014kBarE = external global i32
+//
 // CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant
 // CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE
 // CHECK: @_ZTVN5test018stdio_sync_filebufIwEE = unnamed_addr constant
 
+// CHECK: @_ZN7PR100011SIiE3arrE = weak_odr global [3 x i32]
+// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = weak_odr global [3 x i32]A
+
 // CHECK-NOT: _ZTVN5test31SIiEE
 // CHECK-NOT: _ZTSN5test31SIiEE
 
@@ -122,3 +128,27 @@
 // CHECK-NOT: _ZN6PR85051AILi0EE1B1fEv
 template class A<0>;
 }
+
+// Ensure that when instantiating initializers for static data members to
+// complete their type in an unevaluated context, we *do* emit initializers with
+// side-effects, but *don't* emit initializers and variables which are otherwise
+// unused in the program.
+namespace PR10001 {
+  template <typename T> struct S {
+    static const int arr[];
+    static const int arr2[];
+    static const int x, y;
+    static int f();
+  };
+
+  extern int foo();
+  extern int kBar;
+
+  template <typename T> const int S<T>::arr[] = { 1, 2, foo() }; // possible side effects
+  template <typename T> const int S<T>::arr2[] = { 1, 2, kBar }; // no side effects
+  template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]);
+  template <typename T> const int S<T>::y = sizeof(arr2) / sizeof(arr2[0]);
+  template <typename T> int S<T>::f() { return x + y; }
+
+  int x = S<int>::f();
+}

Modified: cfe/trunk/test/SemaTemplate/instantiate-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-init.cpp?rev=132172&r1=132171&r2=132172&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-init.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-init.cpp Thu May 26 20:33:31 2011
@@ -55,3 +55,21 @@
     f0<int>();
   }
 }
+
+// Instantiate out-of-line definitions of static data members which complete
+// types through an initializer even when the only use of the member that would
+// cause instantiation is in an unevaluated context, but one requiring its
+// complete type.
+namespace PR10001 {
+  template <typename T> struct S {
+    static const int arr[];
+    static const int x;
+    static int f();
+  };
+
+  template <typename T> const int S<T>::arr[] = { 1, 2, 3 };
+  template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]);
+  template <typename T> int S<T>::f() { return x; }
+
+  int x = S<int>::f();
+}





More information about the cfe-commits mailing list