Author: rnk Date: Thu May 10 11:57:35 2018 New Revision: 332018 URL: http://llvm.org/viewvc/llvm-project?rev=332018&view=rev Log: Allow dllimport non-type template arguments in C++17
Summary: Fixes PR35772. Reviewers: rsmith Differential Revision: https://reviews.llvm.org/D43320 Added: cfe/trunk/test/SemaCXX/dllimport-constexpr.cpp Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/Sema/SemaOverload.cpp cfe/trunk/test/SemaCXX/dllimport-memptr.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=332018&r1=332017&r2=332018&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Thu May 10 11:57:35 2018 @@ -658,6 +658,13 @@ public: ArrayRef<const Expr*> Args, const Expr *This = nullptr) const; + /// Indicates how the constant expression will be used. + enum ConstExprUsage { EvaluateForCodeGen, EvaluateForMangling }; + + /// Evaluate an expression that is required to be a constant expression. + bool EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, + 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 Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=332018&r1=332017&r2=332018&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu May 10 11:57:35 2018 @@ -1720,7 +1720,8 @@ static void NoteLValueLocation(EvalInfo /// value for an address or reference constant expression. Return true if we /// can fold this expression, whether or not it's a constant expression. static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, - QualType Type, const LValue &LVal) { + QualType Type, const LValue &LVal, + Expr::ConstExprUsage Usage) { bool IsReferenceType = Type->isReferenceType(); APValue::LValueBase Base = LVal.getLValueBase(); @@ -1753,7 +1754,7 @@ static bool CheckLValueConstantExpressio return false; // A dllimport variable never acts like a constant. - if (Var->hasAttr<DLLImportAttr>()) + if (Usage == Expr::EvaluateForCodeGen && Var->hasAttr<DLLImportAttr>()) return false; } if (const auto *FD = dyn_cast<const FunctionDecl>(VD)) { @@ -1767,7 +1768,8 @@ static bool CheckLValueConstantExpressio // 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 && Usage == Expr::EvaluateForCodeGen && + FD->hasAttr<DLLImportAttr>()) return false; } } @@ -1800,12 +1802,14 @@ static bool CheckLValueConstantExpressio static bool CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc, QualType Type, - const APValue &Value) { + const APValue &Value, + Expr::ConstExprUsage Usage) { const ValueDecl *Member = Value.getMemberPointerDecl(); const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); if (!FD) return true; - return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); + return Usage == Expr::EvaluateForMangling || FD->isVirtual() || + !FD->hasAttr<DLLImportAttr>(); } /// Check that this core constant expression is of literal type, and if not, @@ -1843,8 +1847,10 @@ static bool CheckLiteralType(EvalInfo &I /// Check that this core constant expression value is a valid value for a /// constant expression. If not, report an appropriate diagnostic. Does not /// check that the expression is of literal type. -static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, - QualType Type, const APValue &Value) { +static bool +CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, + const APValue &Value, + Expr::ConstExprUsage Usage = Expr::EvaluateForCodeGen) { if (Value.isUninit()) { Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized) << true << Type; @@ -1863,28 +1869,28 @@ static bool CheckConstantExpression(Eval QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType(); for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) { if (!CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayInitializedElt(I))) + Value.getArrayInitializedElt(I), Usage)) return false; } if (!Value.hasArrayFiller()) return true; - return CheckConstantExpression(Info, DiagLoc, EltTy, - Value.getArrayFiller()); + return CheckConstantExpression(Info, DiagLoc, EltTy, Value.getArrayFiller(), + Usage); } if (Value.isUnion() && Value.getUnionField()) { return CheckConstantExpression(Info, DiagLoc, Value.getUnionField()->getType(), - Value.getUnionValue()); + Value.getUnionValue(), Usage); } if (Value.isStruct()) { RecordDecl *RD = Type->castAs<RecordType>()->getDecl(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; - for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(), - End = CD->bases_end(); I != End; ++I, ++BaseIndex) { - if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructBase(BaseIndex))) + for (const CXXBaseSpecifier &BS : CD->bases()) { + if (!CheckConstantExpression(Info, DiagLoc, BS.getType(), + Value.getStructBase(BaseIndex), Usage)) return false; + ++BaseIndex; } } for (const auto *I : RD->fields()) { @@ -1892,7 +1898,8 @@ static bool CheckConstantExpression(Eval continue; if (!CheckConstantExpression(Info, DiagLoc, I->getType(), - Value.getStructField(I->getFieldIndex()))) + Value.getStructField(I->getFieldIndex()), + Usage)) return false; } } @@ -1900,11 +1907,11 @@ static bool CheckConstantExpression(Eval if (Value.isLValue()) { LValue LVal; LVal.setFrom(Info.Ctx, Value); - return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); + return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Usage); } if (Value.isMemberPointer()) - return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Usage); // Everything else is fine. return true; @@ -10345,13 +10352,25 @@ bool Expr::EvaluateAsLValue(EvalResult & LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), - Ctx.getLValueReferenceType(getType()), LV)) + Ctx.getLValueReferenceType(getType()), LV, + Expr::EvaluateForCodeGen)) return false; LV.moveInto(Result.Val); return true; } +bool Expr::EvaluateAsConstantExpr(EvalResult &Result, ConstExprUsage Usage, + const ASTContext &Ctx) const { + EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; + EvalInfo Info(Ctx, Result, EM); + if (!::Evaluate(Result.Val, Info, this)) + return false; + + return CheckConstantExpression(Info, getExprLoc(), getType(), Result.Val, + Usage); +} + bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, const VarDecl *VD, SmallVectorImpl<PartialDiagnosticAt> &Notes) const { Modified: cfe/trunk/lib/Sema/SemaOverload.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=332018&r1=332017&r2=332018&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp (original) +++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu May 10 11:57:35 2018 @@ -5407,10 +5407,11 @@ static ExprResult CheckConvertedConstant SmallVector<PartialDiagnosticAt, 8> Notes; Expr::EvalResult Eval; Eval.Diag = &Notes; + Expr::ConstExprUsage Usage = CCE == Sema::CCEK_TemplateArg + ? Expr::EvaluateForMangling + : Expr::EvaluateForCodeGen; - if ((T->isReferenceType() - ? !Result.get()->EvaluateAsLValue(Eval, S.Context) - : !Result.get()->EvaluateAsRValue(Eval, S.Context)) || + if (!Result.get()->EvaluateAsConstantExpr(Eval, Usage, S.Context) || (RequireInt && !Eval.Val.isInt())) { // The expression can't be folded, so we can't keep it at this position in // the AST. Added: cfe/trunk/test/SemaCXX/dllimport-constexpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllimport-constexpr.cpp?rev=332018&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/dllimport-constexpr.cpp (added) +++ cfe/trunk/test/SemaCXX/dllimport-constexpr.cpp Thu May 10 11:57:35 2018 @@ -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(); +} Modified: cfe/trunk/test/SemaCXX/dllimport-memptr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/dllimport-memptr.cpp?rev=332018&r1=332017&r2=332018&view=diff ============================================================================== --- cfe/trunk/test/SemaCXX/dllimport-memptr.cpp (original) +++ cfe/trunk/test/SemaCXX/dllimport-memptr.cpp Thu May 10 11:57:35 2018 @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits