diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-01-14 05:37:29 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-01-14 05:37:29 +0000 |
commit | 21c8fa87a3517d835072193a59a955ec7f6bf408 (patch) | |
tree | 1bd5c804197cdc7053895c89feb7b27aa4b1f320 /lib/Sema | |
parent | 7b19cb116d0909de72dc8242b0a4e6c5ed39d421 (diff) |
PR12008: defer adding the implicit 'const' to a constexpr member function until
we know whether it is static.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172376 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 100 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 47 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 24 |
4 files changed, 111 insertions, 85 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 668b8f8103..7dc413e499 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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)); + } + } - 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 (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()); + } + + // 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)); } } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index cfabccf5fe..cc9f4df447 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index df1521f9c7..67c9ae5e1f 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f44603b1ef..930d98d44a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -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: |