From 74388b4ec07187aebb4264c704c18180b6af8133 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Sat, 4 Feb 2012 00:33:54 +0000 Subject: [PATCH] constexpr: The recent support for potential constant expressions exposed a bug in the implementation of libstdc++4.6, where numeric_limits::min() is defined as (int)1 << 31, which isn't a constant expression. Disable the 'constexpr function never produces a constant expression' error inside system headers to compensate. llvm-svn: 149729 --- clang/lib/AST/ExprConstant.cpp | 3 ++- clang/lib/Sema/SemaDeclCXX.cpp | 21 ++++++++++++++--- clang/test/SemaCXX/constexpr-sysheaders.cpp | 25 +++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-sysheaders.cpp diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a45aea974c79..701e9ccd5638 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -575,7 +575,8 @@ CallStackFrame::~CallStackFrame() { static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) { unsigned ArgIndex = 0; bool IsMemberCall = isa(Frame->Callee) && - !isa(Frame->Callee); + !isa(Frame->Callee) && + cast(Frame->Callee)->isInstance(); if (!IsMemberCall) Out << *Frame->Callee << '('; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index d52ee1283727..7a648939e0a7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -838,13 +838,13 @@ static void CheckConstexprCtorInitializer(Sema &SemaRef, /// \return true if the body is OK, false if we have diagnosed a problem. bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { if (isa(Body)) { - // C++0x [dcl.constexpr]p3: + // C++11 [dcl.constexpr]p3: // The definition of a constexpr function shall satisfy the following // constraints: [...] // - its function-body shall be = delete, = default, or a // compound-statement // - // C++0x [dcl.constexpr]p4: + // C++11 [dcl.constexpr]p4: // In the definition of a constexpr constructor, [...] // - its function-body shall not be a function-try-block; Diag(Body->getLocStart(), diag::err_constexpr_function_try_block) @@ -972,8 +972,23 @@ bool Sema::CheckConstexprFunctionBody(const FunctionDecl *Dcl, Stmt *Body) { } } + // C++11 [dcl.constexpr]p5: + // if no function argument values exist such that the function invocation + // substitution would produce a constant expression, the program is + // ill-formed; no diagnostic required. + // C++11 [dcl.constexpr]p3: + // - every constructor call and implicit conversion used in initializing the + // return value shall be one of those allowed in a constant expression. + // C++11 [dcl.constexpr]p4: + // - every constructor involved in initializing non-static data members and + // base class sub-objects shall be a constexpr constructor. + // + // FIXME: We currently disable this check inside system headers, to work + // around early STL implementations which contain constexpr functions which + // can't produce constant expressions. llvm::SmallVector Diags; - if (!Expr::isPotentialConstantExpr(Dcl, Diags)) { + if (!Context.getSourceManager().isInSystemHeader(Dcl->getLocation()) && + !Expr::isPotentialConstantExpr(Dcl, Diags)) { Diag(Dcl->getLocation(), diag::err_constexpr_function_never_constant_expr) << isa(Dcl); for (size_t I = 0, N = Diags.size(); I != N; ++I) diff --git a/clang/test/SemaCXX/constexpr-sysheaders.cpp b/clang/test/SemaCXX/constexpr-sysheaders.cpp new file mode 100644 index 000000000000..5f9a712bc762 --- /dev/null +++ b/clang/test/SemaCXX/constexpr-sysheaders.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify -include %s %s + +// libstdc++4.6 has a broken numeric_limits with a non-constant min() for signed +// integral types. Disable the 'never produces a constant expression' error in +// system headers to work around it. We still won't treat the function as +// producing a constant expression, though. + +#ifndef INCLUDED_HEADER +#define INCLUDED_HEADER + +#pragma GCC system_header + +// An approximation of libstdc++4.6's broken definition of numeric_limits. +// FIXME: In the -include case, the line numbers are off by one for some reason! +struct numeric_limits { // expected-note {{value 2147483648 is outside the range}} + static constexpr int min() throw() { return (int)1 << (sizeof(int) * 8 - 1); } // no-error + // expected-note {{in call to 'min()'}} + static constexpr int lowest() throw() { return min(); } +}; + +#else + +constexpr int k = numeric_limits::lowest(); // expected-error {{constant expression}} expected-note {{in call to 'lowest()'}} + +#endif -- GitLab