rnk updated this revision to Diff 146025.
rnk added a comment.
- don't expose CCEK, use a bool
https://reviews.llvm.org/D43320
Files:
clang/include/clang/AST/Expr.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
@@ -5408,9 +5408,8 @@
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 == Sema::CCEK_TemplateArg, 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
@@ -704,6 +704,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,
@@ -793,6 +797,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
@@ -845,6 +857,7 @@
LLVM_FALLTHROUGH;
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
+ case EM_TemplateArgument:
case EM_ConstantExpressionUnevaluated:
case EM_PotentialConstantExpressionUnevaluated:
case EM_OffsetFold:
@@ -937,6 +950,7 @@
return true;
case EM_ConstantExpression:
+ case EM_TemplateArgument:
case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
case EM_OffsetFold:
@@ -964,6 +978,7 @@
case EM_PotentialConstantExpression:
case EM_PotentialConstantExpressionUnevaluated:
case EM_ConstantExpression:
+ case EM_TemplateArgument:
case EM_ConstantExpressionUnevaluated:
return false;
}
@@ -991,6 +1006,7 @@
return true;
case EM_ConstantExpression:
+ case EM_TemplateArgument:
case EM_ConstantExpressionUnevaluated:
case EM_ConstantFold:
case EM_IgnoreSideEffects:
@@ -1753,7 +1769,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)) {
@@ -1767,7 +1783,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;
}
}
@@ -1805,7 +1821,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,
@@ -7808,6 +7824,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:
@@ -10352,6 +10369,34 @@
return true;
}
+bool Expr::EvaluateAsCoreConstExpr(EvalResult &Result, QualType ParamType,
+ bool IsTemplateArg,
+ const ASTContext &Ctx) const {
+ EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
+ if (IsTemplateArg)
+ 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/AST/Expr.h
===================================================================
--- clang/include/clang/AST/Expr.h
+++ clang/include/clang/AST/Expr.h
@@ -658,6 +658,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,
+ bool IsTemplateArg, const ASTContext &Ctx) const;
+
/// 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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits