rnk updated this revision to Diff 134510.
rnk added a comment.

- revise as discussed


https://reviews.llvm.org/D43320

Files:
  clang/include/clang/AST/Expr.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ExprConstant.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaCXX/dllimport-constexpr.cpp
  clang/test/SemaCXX/dllimport-memptr.cpp

Index: clang/test/SemaCXX/dllimport-memptr.cpp
===================================================================
--- clang/test/SemaCXX/dllimport-memptr.cpp
+++ clang/test/SemaCXX/dllimport-memptr.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -verify -std=c++17 %s
 
 // expected-no-diagnostics
 
Index: clang/test/SemaCXX/dllimport-constexpr.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/dllimport-constexpr.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++14 %s -verify -fms-extensions -triple x86_64-windows-msvc
+// RUN: %clang_cc1 -std=c++17 %s -verify -fms-extensions -triple x86_64-windows-msvc
+
+__declspec(dllimport) void imported_func();
+__declspec(dllimport) int imported_int;
+struct Foo {
+  void __declspec(dllimport) imported_method();
+};
+
+// Instantiation is OK.
+template <void (*FP)()> struct TemplateFnPtr {
+  static void getit() { FP(); }
+};
+template <void (&FP)()> struct TemplateFnRef {
+  static void getit() { FP(); }
+};
+void instantiate1() {
+  TemplateFnPtr<&imported_func>::getit();
+  TemplateFnRef<imported_func>::getit();
+}
+
+// Check variable template instantiation.
+template <int *GI> struct TemplateIntPtr {
+  static int getit() { return *GI; }
+};
+template <int &GI> struct TemplateIntRef {
+  static int getit() { return GI; }
+};
+int instantiate2() {
+  int r = 0;
+  r += TemplateIntPtr<&imported_int>::getit();
+  r += TemplateIntRef<imported_int>::getit();
+  return r;
+}
+
+// Member pointer instantiation.
+template <void (Foo::*MP)()> struct TemplateMemPtr { };
+TemplateMemPtr<&Foo::imported_method> instantiate_mp;
+
+// constexpr initialization doesn't work for dllimport things.
+// expected-error@+1{{must be initialized by a constant expression}}
+constexpr void (*constexpr_import_func)() = &imported_func;
+// expected-error@+1{{must be initialized by a constant expression}}
+constexpr int *constexpr_import_int = &imported_int;
+// expected-error@+1{{must be initialized by a constant expression}}
+constexpr void (Foo::*constexpr_memptr)() = &Foo::imported_method;
+
+// We make dynamic initializers for 'const' globals, but not constexpr ones.
+void (*const const_import_func)() = &imported_func;
+int *const const_import_int = &imported_int;
+void (Foo::*const const_memptr)() = &Foo::imported_method;
+
+// Check that using a non-type template parameter for constexpr global
+// initialization is correctly diagnosed during template instantiation.
+template <void (*FP)()> struct StaticConstexpr {
+  // expected-error@+1{{must be initialized by a constant expression}}
+  static constexpr void (*g_fp)() = FP;
+};
+void instantiate3() {
+  // expected-note@+1 {{requested here}}
+  StaticConstexpr<imported_func>::g_fp();
+}
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -5297,7 +5297,7 @@
 /// the converted expression, per C++11 [expr.const]p3.
 static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
                                                    QualType T, APValue &Value,
-                                                   Sema::CCEKind CCE,
+                                                   CCEKind CCE,
                                                    bool RequireInt) {
   assert(S.getLangOpts().CPlusPlus11 &&
          "converted constant expression outside C++11");
@@ -5315,7 +5315,7 @@
   //  condition shall be a contextually converted constant expression of type
   //  bool.
   ImplicitConversionSequence ICS =
-      CCE == Sema::CCEK_ConstexprIf
+      CCE == CCEK_ConstexprIf
           ? TryContextuallyConvertToBool(S, From)
           : TryCopyInitialization(S, From, T,
                                   /*SuppressUserConversions=*/false,
@@ -5398,9 +5398,7 @@
   Expr::EvalResult Eval;
   Eval.Diag = &Notes;
 
-  if ((T->isReferenceType()
-           ? !Result.get()->EvaluateAsLValue(Eval, S.Context)
-           : !Result.get()->EvaluateAsRValue(Eval, S.Context)) ||
+  if (!Result.get()->EvaluateAsCoreConstExpr(Eval, T, CCE, S.Context) ||
       (RequireInt && !Eval.Val.isInt())) {
     // The expression can't be folded, so we can't keep it at this position in
     // the AST.
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -649,6 +649,10 @@
       /// a constant expression.
       EM_PotentialConstantExpression,
 
+      /// Evaluate as a C++17 non-type template argument, which is a core
+      /// constant expression with a special case for dllimport declarations.
+      EM_TemplateArgument,
+
       /// Fold the expression to a constant. Stop if we hit a side-effect that
       /// we can't model.
       EM_ConstantFold,
@@ -738,6 +742,14 @@
       return false;
     }
 
+    /// Return true if this declaration is dllimport and we cannot treat the
+    /// address as a constant expression. Generally, we do not want to constant
+    /// fold dllimport declarations unless they are used in a non-type template
+    /// parameter.
+    bool isNonConstDllImportDecl(const Decl *D) {
+      return EvalMode != EM_TemplateArgument && D->hasAttr<DLLImportAttr>();
+    }
+
     CallStackFrame *getCallFrame(unsigned CallIndex) {
       assert(CallIndex && "no call index in getCallFrame");
       // We will eventually hit BottomFrame, which has Index 1, so Frame can't
@@ -790,6 +802,7 @@
             LLVM_FALLTHROUGH;
           case EM_ConstantExpression:
           case EM_PotentialConstantExpression:
+          case EM_TemplateArgument:
           case EM_ConstantExpressionUnevaluated:
           case EM_PotentialConstantExpressionUnevaluated:
           case EM_OffsetFold:
@@ -882,6 +895,7 @@
         return true;
 
       case EM_ConstantExpression:
+      case EM_TemplateArgument:
       case EM_ConstantExpressionUnevaluated:
       case EM_ConstantFold:
       case EM_OffsetFold:
@@ -909,6 +923,7 @@
       case EM_PotentialConstantExpression:
       case EM_PotentialConstantExpressionUnevaluated:
       case EM_ConstantExpression:
+      case EM_TemplateArgument:
       case EM_ConstantExpressionUnevaluated:
         return false;
       }
@@ -936,6 +951,7 @@
         return true;
 
       case EM_ConstantExpression:
+      case EM_TemplateArgument:
       case EM_ConstantExpressionUnevaluated:
       case EM_ConstantFold:
       case EM_IgnoreSideEffects:
@@ -1686,7 +1702,7 @@
         return false;
 
       // A dllimport variable never acts like a constant.
-      if (Var->hasAttr<DLLImportAttr>())
+      if (Info.isNonConstDllImportDecl(Var))
         return false;
     }
     if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) {
@@ -1700,7 +1716,7 @@
       // The C language has no notion of ODR; furthermore, it has no notion of
       // dynamic initialization.  This means that we are permitted to
       // perform initialization with the address of the thunk.
-      if (Info.getLangOpts().CPlusPlus && FD->hasAttr<DLLImportAttr>())
+      if (Info.getLangOpts().CPlusPlus && Info.isNonConstDllImportDecl(FD))
         return false;
     }
   }
@@ -1738,7 +1754,7 @@
   const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
   if (!FD)
     return true;
-  return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>();
+  return FD->isVirtual() || !Info.isNonConstDllImportDecl(FD);
 }
 
 /// Check that this core constant expression is of literal type, and if not,
@@ -7684,6 +7700,7 @@
     // size of the referenced object.
     switch (Info.EvalMode) {
     case EvalInfo::EM_ConstantExpression:
+    case EvalInfo::EM_TemplateArgument:
     case EvalInfo::EM_PotentialConstantExpression:
     case EvalInfo::EM_ConstantFold:
     case EvalInfo::EM_EvaluateForOverflow:
@@ -10147,6 +10164,33 @@
   return true;
 }
 
+bool Expr::EvaluateAsCoreConstExpr(EvalResult &Result, QualType ParamType,
+                                   CCEKind CCE, const ASTContext &Ctx) const {
+  EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
+  if (CCE == CCEK_TemplateArg)
+    EM = EvalInfo::EM_TemplateArgument;
+
+  // A reference must be an lvalue.
+  if (ParamType->isReferenceType()) {
+    EvalInfo Info(Ctx, Result, EM);
+    LValue LV;
+    if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
+        !CheckLValueConstantExpression(
+            Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV))
+      return false;
+
+    LV.moveInto(Result.Val);
+    return true;
+  }
+
+  // Otherwise, evaluate it as an rvalue.
+  bool IsConst;
+  if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
+    return IsConst;
+  EvalInfo Info(Ctx, Result, EM);
+  return ::EvaluateAsRValue(Info, this, Result.Val);
+}
+
 bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
                                  const VarDecl *VD,
                             SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2582,14 +2582,6 @@
   ExprResult PerformContextuallyConvertToBool(Expr *From);
   ExprResult PerformContextuallyConvertToObjCPointer(Expr *From);
 
-  /// Contexts in which a converted constant expression is required.
-  enum CCEKind {
-    CCEK_CaseValue,   ///< Expression in a case label.
-    CCEK_Enumerator,  ///< Enumerator value with fixed underlying type.
-    CCEK_TemplateArg, ///< Value of a non-type template parameter.
-    CCEK_NewExpr,     ///< Constant expression in a noptr-new-declarator.
-    CCEK_ConstexprIf  ///< Condition in a constexpr if statement.
-  };
   ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
                                               llvm::APSInt &Value, CCEKind CCE);
   ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
Index: clang/include/clang/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -99,6 +99,15 @@
   }
 };
 
+/// Contexts in which a converted constant expression is required.
+enum CCEKind {
+  CCEK_CaseValue,   ///< Expression in a case label.
+  CCEK_Enumerator,  ///< Enumerator value with fixed underlying type.
+  CCEK_TemplateArg, ///< Value of a non-type template parameter.
+  CCEK_NewExpr,     ///< Constant expression in a noptr-new-declarator.
+  CCEK_ConstexprIf  ///< Condition in a constexpr if statement.
+};
+
 /// Expr - This represents one expression.  Note that Expr's are subclasses of
 /// Stmt.  This allows an expression to be transparently used any place a Stmt
 /// is required.
@@ -658,6 +667,10 @@
                                 ArrayRef<const Expr*> Args,
                                 const Expr *This = nullptr) const;
 
+  /// Evaluate an expression that is required to be a core constant expression.
+  bool EvaluateAsCoreConstExpr(EvalResult &Result, QualType ParamType,
+                               CCEKind CCE, const ASTContext &Ctx) const;
+
   /// \brief If the current Expr is a pointer, this will try to statically
   /// determine the number of bytes available where the pointer is pointing.
   /// Returns true if all of the above holds and we were able to figure out the
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D43320: A... Reid Kleckner via Phabricator via cfe-commits
    • [PATCH] D433... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D433... Richard Smith - zygoloid via Phabricator via cfe-commits
    • [PATCH] D433... Reid Kleckner via Phabricator via cfe-commits
    • [PATCH] D433... Reid Kleckner via Phabricator via cfe-commits
    • [PATCH] D433... Richard Smith - zygoloid via Phabricator via cfe-commits

Reply via email to