PR12008: defer adding the implicit 'const' to a constexpr member function until
we know whether it is static. llvm-svn: 172376
This commit is contained in:
parent
01141a95a5
commit
574f4f6a1d
|
@ -5598,11 +5598,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
}
|
||||
|
||||
if (isConstexpr) {
|
||||
// C++0x [dcl.constexpr]p2: constexpr functions and constexpr constructors
|
||||
// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors
|
||||
// are implicitly inline.
|
||||
NewFD->setImplicitlyInline();
|
||||
|
||||
// C++0x [dcl.constexpr]p3: functions declared constexpr are required to
|
||||
// C++11 [dcl.constexpr]p3: functions declared constexpr are required to
|
||||
// be either constructors or to return a literal type. Therefore,
|
||||
// destructors cannot be declared constexpr.
|
||||
if (isa<CXXDestructorDecl>(NewFD))
|
||||
|
@ -6162,6 +6162,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
filterNonConflictingPreviousDecls(Context, NewFD, Previous);
|
||||
|
||||
bool Redeclaration = false;
|
||||
NamedDecl *OldDecl = 0;
|
||||
|
||||
// Merge or overload the declaration with an existing declaration of
|
||||
// the same name, if appropriate.
|
||||
|
@ -6170,8 +6171,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
// a declaration that requires merging. If it's an overload,
|
||||
// there's no more work to do here; we'll just add the new
|
||||
// function to the scope.
|
||||
|
||||
NamedDecl *OldDecl = 0;
|
||||
if (!AllowOverloadingOfFunction(Previous, Context)) {
|
||||
Redeclaration = true;
|
||||
OldDecl = Previous.getFoundDecl();
|
||||
|
@ -6208,43 +6207,68 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
|
|||
Context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Redeclaration) {
|
||||
// NewFD and OldDecl represent declarations that need to be
|
||||
// merged.
|
||||
if (MergeFunctionDecl(NewFD, OldDecl, S)) {
|
||||
NewFD->setInvalidDecl();
|
||||
return Redeclaration;
|
||||
// C++11 [dcl.constexpr]p8:
|
||||
// A constexpr specifier for a non-static member function that is not
|
||||
// a constructor declares that member function to be const.
|
||||
//
|
||||
// This needs to be delayed until we know whether this is an out-of-line
|
||||
// definition of a static member function.
|
||||
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewFD);
|
||||
if (MD && MD->isConstexpr() && !MD->isStatic() &&
|
||||
!isa<CXXConstructorDecl>(MD) &&
|
||||
(MD->getTypeQualifiers() & Qualifiers::Const) == 0) {
|
||||
CXXMethodDecl *OldMD = dyn_cast_or_null<CXXMethodDecl>(OldDecl);
|
||||
if (FunctionTemplateDecl *OldTD =
|
||||
dyn_cast_or_null<FunctionTemplateDecl>(OldDecl))
|
||||
OldMD = dyn_cast<CXXMethodDecl>(OldTD->getTemplatedDecl());
|
||||
if (!OldMD || !OldMD->isStatic()) {
|
||||
const FunctionProtoType *FPT =
|
||||
MD->getType()->castAs<FunctionProtoType>();
|
||||
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
|
||||
EPI.TypeQuals |= Qualifiers::Const;
|
||||
MD->setType(Context.getFunctionType(FPT->getResultType(),
|
||||
FPT->arg_type_begin(),
|
||||
FPT->getNumArgs(), EPI));
|
||||
}
|
||||
}
|
||||
|
||||
if (Redeclaration) {
|
||||
// NewFD and OldDecl represent declarations that need to be
|
||||
// merged.
|
||||
if (MergeFunctionDecl(NewFD, OldDecl, S)) {
|
||||
NewFD->setInvalidDecl();
|
||||
return Redeclaration;
|
||||
}
|
||||
|
||||
Previous.clear();
|
||||
Previous.addDecl(OldDecl);
|
||||
|
||||
if (FunctionTemplateDecl *OldTemplateDecl
|
||||
= dyn_cast<FunctionTemplateDecl>(OldDecl)) {
|
||||
NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
|
||||
FunctionTemplateDecl *NewTemplateDecl
|
||||
= NewFD->getDescribedFunctionTemplate();
|
||||
assert(NewTemplateDecl && "Template/non-template mismatch");
|
||||
if (CXXMethodDecl *Method
|
||||
= dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
|
||||
Method->setAccess(OldTemplateDecl->getAccess());
|
||||
NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
|
||||
}
|
||||
|
||||
Previous.clear();
|
||||
Previous.addDecl(OldDecl);
|
||||
|
||||
if (FunctionTemplateDecl *OldTemplateDecl
|
||||
= dyn_cast<FunctionTemplateDecl>(OldDecl)) {
|
||||
NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
|
||||
FunctionTemplateDecl *NewTemplateDecl
|
||||
= NewFD->getDescribedFunctionTemplate();
|
||||
assert(NewTemplateDecl && "Template/non-template mismatch");
|
||||
if (CXXMethodDecl *Method
|
||||
= dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
|
||||
Method->setAccess(OldTemplateDecl->getAccess());
|
||||
NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
|
||||
}
|
||||
|
||||
// If this is an explicit specialization of a member that is a function
|
||||
// template, mark it as a member specialization.
|
||||
if (IsExplicitSpecialization &&
|
||||
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
|
||||
NewTemplateDecl->setMemberSpecialization();
|
||||
assert(OldTemplateDecl->isMemberSpecialization());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
|
||||
NewFD->setAccess(OldDecl->getAccess());
|
||||
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
||||
|
||||
// If this is an explicit specialization of a member that is a function
|
||||
// template, mark it as a member specialization.
|
||||
if (IsExplicitSpecialization &&
|
||||
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
|
||||
NewTemplateDecl->setMemberSpecialization();
|
||||
assert(OldTemplateDecl->isMemberSpecialization());
|
||||
}
|
||||
|
||||
} else {
|
||||
if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions
|
||||
NewFD->setAccess(OldDecl->getAccess());
|
||||
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1012,28 +1012,37 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
|
|||
// 13.1p2). While not part of the definition of the signature,
|
||||
// this check is important to determine whether these functions
|
||||
// can be overloaded.
|
||||
CXXMethodDecl* OldMethod = dyn_cast<CXXMethodDecl>(Old);
|
||||
CXXMethodDecl* NewMethod = dyn_cast<CXXMethodDecl>(New);
|
||||
CXXMethodDecl *OldMethod = dyn_cast<CXXMethodDecl>(Old);
|
||||
CXXMethodDecl *NewMethod = dyn_cast<CXXMethodDecl>(New);
|
||||
if (OldMethod && NewMethod &&
|
||||
!OldMethod->isStatic() && !NewMethod->isStatic() &&
|
||||
(OldMethod->getTypeQualifiers() != NewMethod->getTypeQualifiers() ||
|
||||
OldMethod->getRefQualifier() != NewMethod->getRefQualifier())) {
|
||||
if (!UseUsingDeclRules &&
|
||||
OldMethod->getRefQualifier() != NewMethod->getRefQualifier() &&
|
||||
(OldMethod->getRefQualifier() == RQ_None ||
|
||||
NewMethod->getRefQualifier() == RQ_None)) {
|
||||
// C++0x [over.load]p2:
|
||||
// - Member function declarations with the same name and the same
|
||||
// parameter-type-list as well as member function template
|
||||
// declarations with the same name, the same parameter-type-list, and
|
||||
// the same template parameter lists cannot be overloaded if any of
|
||||
// them, but not all, have a ref-qualifier (8.3.5).
|
||||
Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
|
||||
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
|
||||
Diag(OldMethod->getLocation(), diag::note_previous_declaration);
|
||||
!OldMethod->isStatic() && !NewMethod->isStatic()) {
|
||||
if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) {
|
||||
if (!UseUsingDeclRules &&
|
||||
(OldMethod->getRefQualifier() == RQ_None ||
|
||||
NewMethod->getRefQualifier() == RQ_None)) {
|
||||
// C++0x [over.load]p2:
|
||||
// - Member function declarations with the same name and the same
|
||||
// parameter-type-list as well as member function template
|
||||
// declarations with the same name, the same parameter-type-list, and
|
||||
// the same template parameter lists cannot be overloaded if any of
|
||||
// them, but not all, have a ref-qualifier (8.3.5).
|
||||
Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload)
|
||||
<< NewMethod->getRefQualifier() << OldMethod->getRefQualifier();
|
||||
Diag(OldMethod->getLocation(), diag::note_previous_declaration);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
// We may not have applied the implicit const for a constexpr member
|
||||
// function yet (because we haven't yet resolved whether this is a static
|
||||
// or non-static member function). Add it now, on the assumption that this
|
||||
// is a redeclaration of OldMethod.
|
||||
unsigned NewQuals = NewMethod->getTypeQualifiers();
|
||||
if ((OldMethod->isConstexpr() || NewMethod->isConstexpr()) &&
|
||||
!isa<CXXConstructorDecl>(NewMethod))
|
||||
NewQuals |= Qualifiers::Const;
|
||||
if (OldMethod->getTypeQualifiers() != NewQuals)
|
||||
return true;
|
||||
}
|
||||
|
||||
// The signatures match; this is not an overload.
|
||||
|
|
|
@ -5918,6 +5918,25 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
|
|||
Ovl->getDeclContext()->getRedeclContext()))
|
||||
continue;
|
||||
|
||||
// When matching a constexpr member function template specialization
|
||||
// against the primary template, we don't yet know whether the
|
||||
// specialization has an implicit 'const' (because we don't know whether
|
||||
// it will be a static member function until we know which template it
|
||||
// specializes), so adjust it now assuming it specializes this template.
|
||||
QualType FT = FD->getType();
|
||||
if (FD->isConstexpr()) {
|
||||
CXXMethodDecl *OldMD =
|
||||
dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
|
||||
if (OldMD && OldMD->isConst()) {
|
||||
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
|
||||
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
|
||||
EPI.TypeQuals |= Qualifiers::Const;
|
||||
FT = Context.getFunctionType(FPT->getResultType(),
|
||||
FPT->arg_type_begin(),
|
||||
FPT->getNumArgs(), EPI);
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [temp.expl.spec]p11:
|
||||
// A trailing template-argument can be left unspecified in the
|
||||
// template-id naming an explicit function template specialization
|
||||
|
@ -5928,10 +5947,8 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
|
|||
TemplateDeductionInfo Info(FD->getLocation());
|
||||
FunctionDecl *Specialization = 0;
|
||||
if (TemplateDeductionResult TDK
|
||||
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs,
|
||||
FD->getType(),
|
||||
Specialization,
|
||||
Info)) {
|
||||
= DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, FT,
|
||||
Specialization, Info)) {
|
||||
// FIXME: Template argument deduction failed; record why it failed, so
|
||||
// that we can provide nifty diagnostics.
|
||||
(void)TDK;
|
||||
|
|
|
@ -2690,30 +2690,6 @@ 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.
|
||||
// FIXME: This should be deferred until we know whether this is a static
|
||||
// member function (for an out-of-class definition, we don't know
|
||||
// this until we perform redeclaration lookup).
|
||||
if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction &&
|
||||
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static &&
|
||||
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);
|
||||
// Rebuild any parens around the identifier in the function type.
|
||||
for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
|
||||
if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren)
|
||||
break;
|
||||
T = S.BuildParenType(T);
|
||||
}
|
||||
}
|
||||
|
||||
// C++11 [dcl.fct]p6 (w/DR1417):
|
||||
// An attempt to specify a function type with a cv-qualifier-seq or a
|
||||
// ref-qualifier (including by typedef-name) is ill-formed unless it is:
|
||||
|
|
|
@ -1,19 +1,35 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||
|
||||
using size_t = decltype(sizeof(int));
|
||||
|
||||
struct S {
|
||||
constexpr int f();
|
||||
constexpr int g() const;
|
||||
static constexpr int Sf();
|
||||
/*static*/ constexpr void *operator new(size_t) noexcept;
|
||||
template<typename T> constexpr T tm();
|
||||
template<typename T> static constexpr T ts();
|
||||
};
|
||||
|
||||
void f(const S &s) {
|
||||
s.f();
|
||||
s.g();
|
||||
|
||||
int (*f)() = &S::Sf;
|
||||
int (*Sf)() = &S::Sf;
|
||||
int (S::*f)() const = &S::f;
|
||||
int (S::*g)() const = &S::g;
|
||||
void *(*opNew)(size_t) = &S::operator new;
|
||||
int (S::*tm)() const = &S::tm;
|
||||
int (*ts)() = &S::ts;
|
||||
}
|
||||
|
||||
constexpr int S::f() const { return 0; }
|
||||
constexpr int S::g() { return 1; }
|
||||
constexpr int S::Sf() { return 2; }
|
||||
constexpr void *S::operator new(size_t) noexcept { return 0; }
|
||||
template<typename T> constexpr T S::tm() { return T(); }
|
||||
template<typename T> constexpr T S::ts() { return T(); }
|
||||
|
||||
namespace std_example {
|
||||
|
||||
class debug_flag { // expected-note {{not an aggregate and has no constexpr constructors}}
|
||||
|
|
|
@ -12,7 +12,7 @@ struct Y {
|
|||
constexpr int f() { return 0; }
|
||||
};
|
||||
|
||||
template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
|
||||
template constexpr int Y<int>::f() const; // expected-error{{explicit instantiation cannot be 'constexpr'}}
|
||||
|
||||
template<typename T>
|
||||
struct Z {
|
||||
|
|
Loading…
Reference in New Issue