ehsan updated this revision to Diff 47021.
ehsan added a comment.

Addressed the review comments.


http://reviews.llvm.org/D16465

Files:
  include/clang/AST/Decl.h
  include/clang/AST/Expr.h
  include/clang/Basic/DiagnosticASTKinds.td
  lib/AST/Decl.cpp
  lib/AST/ExprConstant.cpp
  lib/CodeGen/CGExprConstant.cpp
  test/CodeGenCXX/static-init-msvc.cpp

Index: test/CodeGenCXX/static-init-msvc.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/static-init-msvc.cpp
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 -triple i686-windows-msvc -std=c++11 -fms-extensions -emit-llvm -O0 -w -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -std=c++11 -fms-extensions -emit-llvm -O0 -w -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple i686-windows-gnu -std=c++11 -fms-extensions -emit-llvm -O0 -w -o - %s | FileCheck %s --check-prefix GNU
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -std=c++11 -fms-extensions -emit-llvm -O0 -w -o - %s | FileCheck %s --check-prefix GNU
+
+void fun_and() {
+// CHECK-LABEL: @"\01?fun_and@@YAXXZ"()
+// GNU-LABEL: @_Z7fun_andv()
+  static int k;
+  static const int foo = 0 && k;
+// CHECK: init:
+// CHECK-NEXT: store i32 0, i32* @"\01?foo@?1??fun_and@@YAXXZ@4HB", align 4
+// GNU: entry:
+// GNU-NEXT: ret void
+}
+
+void fun_or() {
+// CHECK-LABEL: @"\01?fun_or@@YAXXZ"()
+// GNU-LABEL: @_Z6fun_orv()
+  static int k;
+  static const int foo = 1 || k;
+// CHECK: init:
+// CHECK-NEXT: store i32 1, i32* @"\01?foo@?1??fun_or@@YAXXZ@4HB", align 4
+// GNU: entry:
+// GNU-NEXT: ret void
+}
+
+void fun_comma() {
+// CHECK-LABEL: @"\01?fun_comma@@YAXXZ"()
+// GNU-LABEL: @_Z9fun_commav()
+  static int k;
+  static const int foo = (k, 0);
+// CHECK: init:
+// CHECK-NEXT: store i32 0, i32* @"\01?foo@?1??fun_comma@@YAXXZ@4HB", align 4
+// GNU: entry:
+// GNU-NEXT: ret void
+}
+
+void fun_not() {
+// CHECK-LABEL: @"\01?fun_not@@YAXXZ"()
+// GNU-LABEL: @_Z7fun_notv()
+  static int k;
+  static const bool foo = !&k;
+// CHECK: init:
+// CHECK-NEXT: store i8 0, i8* @"\01?foo@?1??fun_not@@YAXXZ@4_NB", align 1
+// GNU: entry:
+// GNU-NEXT: ret void
+}
+
+void fun_cond() {
+// CHECK-LABEL: @"\01?fun_cond@@YAXXZ"()
+// GNU-LABEL: @_Z8fun_condv()
+  static int k;
+  static const int foo = true ? 0 : k;
+// CHECK: init:
+// CHECK-NEXT: store i32 0, i32* @"\01?foo@?1??fun_cond@@YAXXZ@4HB", align 4
+// GNU: entry:
+// GNU-NEXT: ret void
+}
+
+void fun_constexpr() {
+  // Here we are willfully violating the Microsoft ABI, since the user has
+  // asked for constexpr explicitly...
+
+// CHECK-LABEL: @"\01?fun_constexpr@@YAXXZ"()
+// GNU-LABEL: @_Z13fun_constexprv()
+  static int k;
+  static constexpr int *p = true ? 0 : &k;
+// GNU: entry:
+// GNU-NEXT: ret void
+}
Index: lib/CodeGen/CGExprConstant.cpp
===================================================================
--- lib/CodeGen/CGExprConstant.cpp
+++ lib/CodeGen/CGExprConstant.cpp
@@ -1190,8 +1190,8 @@
           return EmitNullConstant(D.getType());
       }
   }
-  
-  if (const APValue *Value = D.evaluateValue())
+
+  if (const APValue *Value = D.evaluateValue(true))
     return EmitConstantValueForMemory(*Value, D.getType(), CGF);
 
   // FIXME: Implement C++11 [basic.start.init]p2: if the initializer of a
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -477,6 +477,19 @@
     /// fold (not just why it's not strictly a constant expression)?
     bool HasFoldFailureDiagnostic;
 
+    /// \brief True if we need to obey the Microsoft ABI.  This affects whether
+    /// some expressions can be evaluated as a constant if they refer to
+    /// variables in some cases.  See PR26210 for the discussion.
+    bool IsMicrosoftABI;
+
+    /// \brief True if we are looking for a DeclRefExpr.
+    bool LookingForDeclRefExpr;
+
+    /// \brief True if we have observed a DeclRefExpr since the last time that
+    /// awaitDeclRefExpr() was called.  This is used in order to handle Microsoft
+    /// ABI requirements.
+    bool HaveSeenDeclRefExpr;
+
     enum EvaluationMode {
       /// Evaluate as a constant expression. Stop if we find that the expression
       /// is not a constant expression.
@@ -541,7 +554,9 @@
         BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
         EvaluatingDecl((const ValueDecl *)nullptr),
         EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
-        HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
+        HasFoldFailureDiagnostic(false), IsMicrosoftABI(false),
+        LookingForDeclRefExpr(false), HaveSeenDeclRefExpr(false),
+        EvalMode(Mode) {}
 
     void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
       EvaluatingDecl = Base;
@@ -766,6 +781,22 @@
     bool allowInvalidBaseExpr() const {
       return EvalMode == EM_DesignatorFold;
     }
+
+    /// Use the Microsoft ABI during evaluation.
+    void useMicrosoftABI() {
+      IsMicrosoftABI = true;
+    }
+
+    /// Start watching for a DeclRefExpr.
+    void awaitDeclRefExpr() {
+      LookingForDeclRefExpr = true;
+      HaveSeenDeclRefExpr = false;
+    }
+
+    /// Remember that we have observed a DeclRefExpr.
+    void noteDeclRefExpr() {
+      HaveSeenDeclRefExpr = true;
+    }
   };
 
   /// Object used to treat all foldable expressions as constant expressions.
@@ -814,13 +845,14 @@
   /// RAII object used to suppress diagnostics and side-effects from a
   /// speculative evaluation.
   class SpeculativeEvaluationRAII {
-    EvalInfo &Info;
     Expr::EvalStatus Old;
+  protected:
+    EvalInfo &Info;
 
   public:
     SpeculativeEvaluationRAII(EvalInfo &Info,
                         SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
-      : Info(Info), Old(Info.EvalStatus) {
+      : Old(Info.EvalStatus), Info(Info) {
       Info.EvalStatus.Diag = NewDiag;
       // If we're speculatively evaluating, we may have skipped over some
       // evaluations and missed out a side effect.
@@ -831,6 +863,18 @@
     }
   };
 
+  class SpeculativeLookForDeclRefExprRAII final : SpeculativeEvaluationRAII {
+  public:
+    SpeculativeLookForDeclRefExprRAII(EvalInfo &Info,
+                           SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
+      : SpeculativeEvaluationRAII(Info, NewDiag) {
+      Info.awaitDeclRefExpr();
+    }
+    ~SpeculativeLookForDeclRefExprRAII() {
+      Info.LookingForDeclRefExpr = false;
+    }
+  };
+
   /// RAII object wrapping a full-expression or block scope, and handling
   /// the ending of the lifetime of temporaries created within it.
   template<bool IsFullExpression>
@@ -4050,6 +4094,13 @@
     }
 
     Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+    if (Info.IsMicrosoftABI) {
+      // In the Microsoft ABI, a DeclRefExpr on either side of the conditional
+      // operator will prevent us from evaluating the expression to a constant.
+      if (!CheckPotentialExpressionContainingDeclRefExpr(E->getTrueExpr(),
+                                                         E->getFalseExpr()))
+        return false;
+    }
     return StmtVisitorTy::Visit(EvalExpr);
   }
 
@@ -4064,6 +4115,31 @@
 
   bool ZeroInitialization(const Expr *E) { return Error(E); }
 
+  // Check whether an expression contains a DeclRefExpr where not permitted by
+  // the Microsoft ABI.
+  template<typename Expr>
+  bool CheckPotentialExpressionContainingDeclRefExpr(const Expr *E) {
+    SmallVector<PartialDiagnosticAt, 8> Diag;
+    SpeculativeLookForDeclRefExprRAII Speculate(Info, &Diag);
+
+    StmtVisitorTy::Visit(E);
+    if (Info.HaveSeenDeclRefExpr) {
+      bool Result = Error(E, diag::note_constexpr_microsoft_abi_declrefexpr);
+      Info.addNotes(Diag);
+      return Result;
+    }
+    return true;
+  }
+
+  // Check whether either of the two expressions contains a DeclRefExpr where
+  // not permitted by the Microsoft ABI.
+  template<typename ExprLHS, typename ExprRHS>
+  bool CheckPotentialExpressionContainingDeclRefExpr(const ExprLHS *ELHS,
+                                                     const ExprRHS *ERHS) {
+    return CheckPotentialExpressionContainingDeclRefExpr(ELHS) &&
+           CheckPotentialExpressionContainingDeclRefExpr(ERHS);
+  }
+
 public:
   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
 
@@ -4626,6 +4702,8 @@
 }
 
 bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+  Info.noteDeclRefExpr();
+
   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl()))
     return Success(FD);
   if (const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
@@ -6069,6 +6147,8 @@
 
   bool CheckReferencedDecl(const Expr *E, const Decl *D);
   bool VisitDeclRefExpr(const DeclRefExpr *E) {
+    Info.noteDeclRefExpr();
+
     if (CheckReferencedDecl(E, E->getDecl()))
       return true;
 
@@ -7186,6 +7266,20 @@
 }
 
 bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+    if (Info.IsMicrosoftABI) {
+      switch (E->getOpcode()) {
+      case BO_Comma:
+      case BO_LAnd:
+      case BO_LOr:
+        // In the Microsoft ABI, a DeclRefExpr on either side of some binary
+        // operators will prevent us from evaluating the expression to a constant.
+        if (!CheckPotentialExpressionContainingDeclRefExpr(E->getLHS(), E->getRHS()))
+          return false;
+      default:
+        /* No need to do anything. */ ;
+      }
+    }
+
   if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp())
     return Error(E);
 
@@ -7710,6 +7804,11 @@
     return Success(~Result.getInt(), E);
   }
   case UO_LNot: {
+    // In the Microsoft ABI, a DeclRefExpr on either side of some binary
+    // operators will prevent us from evaluating the expression to a constant.
+    if (Info.IsMicrosoftABI &&
+        !CheckPotentialExpressionContainingDeclRefExpr(E->getSubExpr()))
+      return false;
     bool bres;
     if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
       return false;
@@ -8900,7 +8999,8 @@
 
 bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
                                  const VarDecl *VD,
-                            SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+                            SmallVectorImpl<PartialDiagnosticAt> &Notes,
+                            bool RespectMicrosoftABIIfNeeded) const {
   // FIXME: Evaluating initializers for large array and record types can cause
   // performance problems. Only do so in C++11 for now.
   if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
@@ -8915,6 +9015,11 @@
                                       : EvalInfo::EM_ConstantFold);
   InitInfo.setEvaluatingDecl(VD, Value);
 
+  if (RespectMicrosoftABIIfNeeded &&
+      Ctx.getTargetInfo().getCXXABI().isMicrosoft() &&
+      VD->isStaticLocal())
+    InitInfo.useMicrosoftABI();
+
   LValue LVal;
   LVal.set(VD);
 
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2137,9 +2137,9 @@
   return Eval;
 }
 
-APValue *VarDecl::evaluateValue() const {
+APValue *VarDecl::evaluateValue(bool RespectMicrosoftABIIfNeeded) const {
   SmallVector<PartialDiagnosticAt, 8> Notes;
-  return evaluateValue(Notes);
+  return evaluateValue(Notes, RespectMicrosoftABIIfNeeded);
 }
 
 namespace {
@@ -2150,13 +2150,17 @@
 } // namespace
 
 APValue *VarDecl::evaluateValue(
-    SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+    SmallVectorImpl<PartialDiagnosticAt> &Notes,
+    bool RespectMicrosoftABIIfNeeded) const {
   EvaluatedStmt *Eval = ensureEvaluatedStmt();
 
   // We only produce notes indicating why an initializer is non-constant the
   // first time it is evaluated. FIXME: The notes won't always be emitted the
   // first time we try evaluation, so might not be produced at all.
-  if (Eval->WasEvaluated)
+  // In case the caller asked us to respect Microsoft ABI requirements, we
+  // never cache the result in Eval, so we have to perform the evaluation
+  // every time.
+  if (Eval->WasEvaluated && !RespectMicrosoftABIIfNeeded)
     return Eval->Evaluated.isUninit() ? nullptr : &Eval->Evaluated;
 
   const auto *Init = cast<Expr>(Eval->Value);
@@ -2172,7 +2176,7 @@
   Eval->IsEvaluating = true;
 
   bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
-                                            this, Notes);
+                                            this, Notes, RespectMicrosoftABIIfNeeded);
 
   // Ensure the computed APValue is cleaned up later if evaluation succeeded,
   // or that it's empty (so that there's nothing to clean up) if evaluation
@@ -2183,13 +2187,15 @@
     getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated);
 
   Eval->IsEvaluating = false;
-  Eval->WasEvaluated = true;
-
-  // In C++11, we have determined whether the initializer was a constant
-  // expression as a side-effect.
-  if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
-    Eval->CheckedICE = true;
-    Eval->IsICE = Result && Notes.empty();
+  if (!RespectMicrosoftABIIfNeeded) {
+    Eval->WasEvaluated = true;
+
+    // In C++11, we have determined whether the initializer was a constant
+    // expression as a side-effect.
+    if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
+      Eval->CheckedICE = true;
+      Eval->IsICE = Result && Notes.empty();
+    }
   }
 
   return Result ? &Eval->Evaluated : nullptr;
Index: include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- include/clang/Basic/DiagnosticASTKinds.td
+++ include/clang/Basic/DiagnosticASTKinds.td
@@ -148,6 +148,9 @@
 def note_constexpr_baa_value_insufficient_alignment : Note<
   "value of the aligned pointer (%0) is not a multiple of the asserted %1 "
   "%plural{1:byte|:bytes}1">;
+def note_constexpr_microsoft_abi_declrefexpr : Note<
+  "in the Microsoft ABI static local variables cannot contain references to "
+  "variables">;
 
 def warn_integer_constant_overflow : Warning<
   "overflow in expression; result is %0 with type %1">,
Index: include/clang/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -630,7 +630,8 @@
   /// notes will be produced if the expression is not a constant expression.
   bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
                              const VarDecl *VD,
-                             SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+                             SmallVectorImpl<PartialDiagnosticAt> &Notes,
+                             bool RespectMicrosoftABIIfNeeded) const;
 
   /// EvaluateWithSubstitution - Evaluate an expression as if from the context
   /// of a call to the given function with the given arguments, inside an
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1089,8 +1089,9 @@
   /// declaration, and produce notes explaining why it cannot be evaluated or is
   /// not a constant expression. Returns a pointer to the value if evaluation
   /// succeeded, 0 otherwise.
-  APValue *evaluateValue() const;
-  APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
+  APValue *evaluateValue(bool RespectMicrosoftABIIfNeeded = false) const;
+  APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes,
+                         bool RespectMicrosoftABIIfNeeded = false) const;
 
   /// \brief Return the already-evaluated value of this variable's
   /// initializer, or NULL if the value is not yet known. Returns pointer
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to