From: Richard Smith Date: Fri, 30 Sep 2011 00:45:47 +0000 (+0000) Subject: constexpr functions are implicitly const. More tests to follow. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=55dec868977ccb89cab0286122f9345f63bb5de7;p=clang constexpr functions are implicitly const. More tests to follow. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140831 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 841aa3b59c..7ba2668107 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1794,8 +1794,8 @@ public: } /// \brief Determine whether this function should be inlined, because it is - /// either marked "inline" or is a member function of a C++ class that - /// was defined in the class body. + /// either marked "inline" or "constexpr" or is a member function of a class + /// that was defined in the class body. bool isInlined() const; bool isInlineDefinitionExternallyVisible() const; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5330fb3956..1b974b0c02 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4292,8 +4292,8 @@ def err_defaulted_copy_assign_const_param : Error< "the parameter for this explicitly-defaulted copy assignment operator is " "const, but a member or base requires it to be non-const">; def err_defaulted_copy_assign_quals : Error< - "an explicitly-defaulted copy assignment operator may not have 'const' " - "or 'volatile' qualifiers">; + "an explicitly-defaulted copy assignment operator may not have 'const', " + "'constexpr' or 'volatile' qualifiers">; def err_defaulted_move_ctor_params : Error< "an explicitly-defaulted move constructor must have exactly one parameter">; def err_defaulted_move_ctor_volatile_param : Error< @@ -4318,8 +4318,8 @@ def err_defaulted_move_assign_const_param : Error< "the parameter for an explicitly-defaulted move assignment operator may not " "be const">; def err_defaulted_move_assign_quals : Error< - "an explicitly-defaulted move assignment operator may not have 'const' " - "or 'volatile' qualifiers">; + "an explicitly-defaulted move assignment operator may not have 'const', " + "'constexpr' or 'volatile' qualifiers">; def err_incorrect_defaulted_exception_spec : Error< "exception specification of explicitly defaulted %select{default constructor|" "copy constructor|move constructor|copy assignment operator|move assignment " diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 85112dbe21..480dd3b85a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2325,6 +2325,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FreeFunction = (DC && !DC->isRecord()); } + // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member + // function that is not a constructor declares that function to be const. + if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction && + D.getName().getKind() != UnqualifiedId::IK_ConstructorName && + D.getName().getKind() != UnqualifiedId::IK_ConstructorTemplateId && + !(FnTy->getTypeQuals() & DeclSpec::TQ_const)) { + // Rebuild function type adding a 'const' qualifier. + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + EPI.TypeQuals |= DeclSpec::TQ_const; + T = Context.getFunctionType(FnTy->getResultType(), + FnTy->arg_type_begin(), + FnTy->getNumArgs(), EPI); + } + // C++0x [dcl.fct]p6: // A ref-qualifier shall only be part of the function type for a // non-static member function, the function type to which a pointer to diff --git a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp index 25470779e6..77a3e26de4 100644 --- a/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp +++ b/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p2.cpp @@ -3,6 +3,7 @@ // constexpr functions and constexpr constructors are implicitly inline. struct S { constexpr S(int n); + constexpr int g(); int n; }; @@ -12,9 +13,14 @@ constexpr S f(S s) { return s.n * 2; } +constexpr int S::g() { + return f(*this).n; +} + // CHECK: define linkonce_odr {{.*}} @_Z1f1S( // CHECK: define linkonce_odr {{.*}} @_ZN1SC1Ei( +// CHECK: define linkonce_odr {{.*}} @_ZNK1S1gEv( int g() { - return f(42).n; + return f(42).g(); } diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp index 6b964dba31..55adbf0c12 100644 --- a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp +++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/dcl.fct.def.default/p2.cpp @@ -22,7 +22,7 @@ namespace move { }; struct ConstAssignment { - ConstAssignment& operator=(ConstAssignment&&) const = default; // expected-error {{an explicitly-defaulted move assignment operator may not have 'const' or 'volatile' qualifiers}} + ConstAssignment& operator=(ConstAssignment&&) const = default; // expected-error {{an explicitly-defaulted move assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}} }; } @@ -57,6 +57,6 @@ namespace copy { }; struct ConstAssignment { - ConstAssignment& operator=(const ConstAssignment&) const = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const' or 'volatile' qualifiers}} + ConstAssignment& operator=(const ConstAssignment&) const = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}} }; } diff --git a/test/SemaCXX/cxx0x-cursory-default-delete.cpp b/test/SemaCXX/cxx0x-cursory-default-delete.cpp index 61aee0e456..9d4443c887 100644 --- a/test/SemaCXX/cxx0x-cursory-default-delete.cpp +++ b/test/SemaCXX/cxx0x-cursory-default-delete.cpp @@ -35,7 +35,7 @@ struct bad_decls { bad_decls(volatile bad_decls&) = default; // expected-error {{may not be volatile}} bad_decls&& operator = (bad_decls) = default; // expected-error 2{{lvalue reference}} bad_decls& operator = (volatile bad_decls&) = default; // expected-error {{may not be volatile}} - bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const' or 'volatile' qualifiers}} + bad_decls& operator = (const bad_decls&) const = default; // expected-error {{may not have 'const', 'constexpr' or 'volatile' qualifiers}} }; struct A {}; struct B {};