diff options
-rw-r--r-- | include/clang/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 5 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp | 25 |
4 files changed, 31 insertions, 4 deletions
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d2d61abc7a..8aca77f51a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1016,7 +1016,8 @@ public: }; bool CheckConstexprFunctionDecl(const FunctionDecl *FD, CheckConstexprKind CCK); - bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); + bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body, + bool IsInstantiation); void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); // Returns true if the function declaration is a redeclaration diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6b92b0ad67..172e931153 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7302,7 +7302,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } if (FD && FD->isConstexpr() && !FD->isInvalidDecl() && - !CheckConstexprFunctionBody(FD, Body)) + !CheckConstexprFunctionBody(FD, Body, IsInstantiation)) FD->setInvalidDecl(); assert(ExprCleanupObjects.empty() && "Leftover temporaries in function"); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a52d44c4f2..10883af4b4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -837,7 +837,8 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4. /// /// \return true if the body is OK, false if we have diagnosed a problem. -bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { +bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body, + bool IsInstantiation) { if (isa<CXXTryStmt>(Body)) { // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following @@ -989,7 +990,7 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { // can't produce constant expressions. llvm::SmallVector<PartialDiagnosticAt, 8> Diags; if (!Context.getSourceManager().isInSystemHeader(Dcl->getLocation()) && - !Expr::isPotentialConstantExpr(Dcl, Diags)) { + !IsInstantiation && !Expr::isPotentialConstantExpr(Dcl, Diags)) { Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr) << isa<CXXConstructorDecl>(Dcl); for (size_t I = 0, N = Diags.size(); I != N; ++I) diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp index 43fc887b00..4e7608ec62 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p5.cpp @@ -78,4 +78,29 @@ constexpr bool BcpCall(int n) { } static_assert(BcpCall(0), ""); +// DR1311: A function template which can produce a constant expression, but +// for which a particular specialization cannot, is ok. +template<typename T> constexpr T cmin(T a, T b) { + return a < b ? a : b; +} +int n = cmin(3, 5); // ok + +struct X { + constexpr X() {} + bool operator<(X); // not constexpr +}; + +X x = cmin(X(), X()); // ok, not constexpr + +// Same with other temploids. +template<typename T> +struct Y { + constexpr Y() {} + constexpr int get() { return T(); } +}; +struct Z { operator int(); }; + +int y1 = Y<int>().get(); // ok +int y2 = Y<Z>().get(); // ok + } |