summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2016-12-01 02:11:49 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2016-12-01 02:11:49 +0000
commitbaa4783d310c7a991690795e0fb9b63d4a781003 (patch)
tree4611ab6a56b729824edd8ed05e7b72cf2bc3f7d9
parentb66cb88c2e29cb032d1efe08ad64d1bfa72d3780 (diff)
downloadbcm5719-llvm-baa4783d310c7a991690795e0fb9b63d4a781003.tar.gz
bcm5719-llvm-baa4783d310c7a991690795e0fb9b63d4a781003.zip
PR31081: ignore exception specifications when deducing function template
arguments from a declaration; despite what the standard says, this form of deduction should not be considering exception specifications. llvm-svn: 288301
-rw-r--r--clang/include/clang/Sema/Sema.h11
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp12
-rw-r--r--clang/lib/Sema/SemaOverload.cpp4
-rw-r--r--clang/lib/Sema/SemaTemplate.cpp3
-rw-r--r--clang/lib/Sema/SemaTemplateDeduction.cpp113
-rw-r--r--clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp48
6 files changed, 143 insertions, 48 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 0d8abb56a12..2fa91a3afb8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6515,7 +6515,12 @@ public:
// C++ Template Argument Deduction (C++ [temp.deduct])
//===--------------------------------------------------------------------===//
- QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType);
+ /// Adjust the type \p ArgFunctionType to match the calling convention,
+ /// noreturn, and optionally the exception specification of \p FunctionType.
+ /// Deduction often wants to ignore these properties when matching function
+ /// types.
+ QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType,
+ bool AdjustExceptionSpec = false);
/// \brief Describes the result of template argument deduction.
///
@@ -6624,7 +6629,7 @@ public:
QualType ArgFunctionType,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info,
- bool InOverloadResolution = false);
+ bool IsAddressOfFunction = false);
TemplateDeductionResult
DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
@@ -6637,7 +6642,7 @@ public:
TemplateArgumentListInfo *ExplicitTemplateArgs,
FunctionDecl *&Specialization,
sema::TemplateDeductionInfo &Info,
- bool InOverloadResolution = false);
+ bool IsAddressOfFunction = false);
/// \brief Substitute Replacement for \p auto in \p TypeWithAuto
QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index dfbbf01a515..79b5356d79d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -2319,8 +2319,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
// To perform this comparison, we compute the function type that
// the deallocation function should have, and use that type both
// for template argument deduction and for comparison purposes.
- //
- // FIXME: this comparison should ignore CC and the like.
QualType ExpectedFunctionType;
{
const FunctionProtoType *Proto
@@ -2334,7 +2332,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
FunctionProtoType::ExtProtoInfo EPI;
// FIXME: This is not part of the standard's rule.
EPI.Variadic = Proto->isVariadic();
- EPI.ExceptionSpec.Type = EST_BasicNoexcept;
ExpectedFunctionType
= Context.getFunctionType(Context.VoidTy, ArgTypes, EPI);
@@ -2344,8 +2341,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
DEnd = FoundDelete.end();
D != DEnd; ++D) {
FunctionDecl *Fn = nullptr;
- if (FunctionTemplateDecl *FnTmpl
- = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
+ if (FunctionTemplateDecl *FnTmpl =
+ dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) {
// Perform template argument deduction to try to match the
// expected function type.
TemplateDeductionInfo Info(StartLoc);
@@ -2355,7 +2352,10 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range,
} else
Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl());
- if (Context.hasSameType(Fn->getType(), ExpectedFunctionType))
+ if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(),
+ ExpectedFunctionType,
+ /*AdjustExcpetionSpec*/true),
+ ExpectedFunctionType))
Matches.push_back(std::make_pair(D.getPair(), Fn));
}
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index cf90a343835..5d28d16f11d 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10572,7 +10572,7 @@ private:
= S.DeduceTemplateArguments(FunctionTemplate,
&OvlExplicitTemplateArgs,
TargetFunctionType, Specialization,
- Info, /*InOverloadResolution=*/true)) {
+ Info, /*IsAddressOfFunction*/true)) {
// Make a note of the failed deduction for diagnostics.
FailedCandidates.addCandidate()
.set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(),
@@ -10975,7 +10975,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
if (TemplateDeductionResult Result
= DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs,
Specialization, Info,
- /*InOverloadResolution=*/true)) {
+ /*IsAddressOfFunction*/true)) {
// Make a note of the failed deduction for diagnostics.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate()
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4e941a53b8e..9a6434579f4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -8075,7 +8075,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
NamedDecl *Prev = *P;
if (!HasExplicitTemplateArgs) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
- QualType Adjusted = adjustCCAndNoReturn(R, Method->getType());
+ QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(),
+ /*AdjustExceptionSpec*/true);
if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) {
Matches.clear();
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 11d744b72bd..dc96d3f544e 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3571,25 +3571,42 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
}
QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
- QualType FunctionType) {
+ QualType FunctionType,
+ bool AdjustExceptionSpec) {
if (ArgFunctionType.isNull())
return ArgFunctionType;
const FunctionProtoType *FunctionTypeP =
FunctionType->castAs<FunctionProtoType>();
- CallingConv CC = FunctionTypeP->getCallConv();
- bool NoReturn = FunctionTypeP->getNoReturnAttr();
const FunctionProtoType *ArgFunctionTypeP =
ArgFunctionType->getAs<FunctionProtoType>();
- if (ArgFunctionTypeP->getCallConv() == CC &&
- ArgFunctionTypeP->getNoReturnAttr() == NoReturn)
+
+ FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo();
+ bool Rebuild = false;
+
+ CallingConv CC = FunctionTypeP->getCallConv();
+ if (EPI.ExtInfo.getCC() != CC) {
+ EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC);
+ Rebuild = true;
+ }
+
+ bool NoReturn = FunctionTypeP->getNoReturnAttr();
+ if (EPI.ExtInfo.getNoReturn() != NoReturn) {
+ EPI.ExtInfo = EPI.ExtInfo.withNoReturn(NoReturn);
+ Rebuild = true;
+ }
+
+ if (AdjustExceptionSpec && (FunctionTypeP->hasExceptionSpec() ||
+ ArgFunctionTypeP->hasExceptionSpec())) {
+ EPI.ExceptionSpec = FunctionTypeP->getExtProtoInfo().ExceptionSpec;
+ Rebuild = true;
+ }
+
+ if (!Rebuild)
return ArgFunctionType;
- FunctionType::ExtInfo EI = ArgFunctionTypeP->getExtInfo().withCallingConv(CC);
- EI = EI.withNoReturn(NoReturn);
- ArgFunctionTypeP =
- cast<FunctionProtoType>(Context.adjustFunctionType(ArgFunctionTypeP, EI));
- return QualType(ArgFunctionTypeP, 0);
+ return Context.getFunctionType(ArgFunctionTypeP->getReturnType(),
+ ArgFunctionTypeP->getParamTypes(), EPI);
}
/// \brief Deduce template arguments when taking the address of a function
@@ -3614,14 +3631,17 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType,
/// \param Info the argument will be updated to provide additional information
/// about template argument deduction.
///
+/// \param IsAddressOfFunction If \c true, we are deducing as part of taking
+/// the address of a function template per [temp.deduct.funcaddr] and
+/// [over.over]. If \c false, we are looking up a function template
+/// specialization based on its signature, per [temp.deduct.decl].
+///
/// \returns the result of template argument deduction.
-Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- QualType ArgFunctionType,
- FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info,
- bool InOverloadResolution) {
+Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType,
+ FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
+ bool IsAddressOfFunction) {
if (FunctionTemplate->isInvalidDecl())
return TDK_Invalid;
@@ -3629,8 +3649,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
- if (!InOverloadResolution)
- ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType);
+
+ // When taking the address of a function, we require convertibility of
+ // the resulting function type. Otherwise, we allow arbitrary mismatches
+ // of calling convention, noreturn, and noexcept.
+ if (!IsAddressOfFunction)
+ ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType,
+ /*AdjustExceptionSpec*/true);
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);
@@ -3655,9 +3680,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
Deduced.resize(TemplateParams->size());
// If the function has a deduced return type, substitute it for a dependent
- // type so that we treat it as a non-deduced context in what follows.
+ // type so that we treat it as a non-deduced context in what follows. If we
+ // are looking up by signature, the signature type should also have a deduced
+ // return type, which we instead expect to exactly match.
bool HasDeducedReturnType = false;
- if (getLangOpts().CPlusPlus14 && InOverloadResolution &&
+ if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
Function->getReturnType()->getContainedAutoType()) {
FunctionType = SubstAutoType(FunctionType, Context.DependentTy);
HasDeducedReturnType = true;
@@ -3665,7 +3692,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
if (!ArgFunctionType.isNull()) {
unsigned TDF = TDF_TopLevelParameterTypeList;
- if (InOverloadResolution) TDF |= TDF_InOverloadResolution;
+ if (IsAddressOfFunction)
+ TDF |= TDF_InOverloadResolution;
// Deduce template arguments from the function type.
if (TemplateDeductionResult Result
= DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams,
@@ -3696,16 +3724,27 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TDK_MiscellaneousDeductionFailure;
+ // Adjust the exception specification of the argument again to match the
+ // substituted and resolved type we just formed. (Calling convention and
+ // noreturn can't be dependent, so we don't actually need this for them
+ // right now.)
+ QualType SpecializationType = Specialization->getType();
+ if (!IsAddressOfFunction)
+ ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType,
+ /*AdjustExceptionSpec*/true);
+
// If the requested function type does not match the actual type of the
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
- if (InOverloadResolution && !isSameOrCompatibleFunctionType(
- Context.getCanonicalType(Specialization->getType()),
- Context.getCanonicalType(ArgFunctionType)))
+ if (IsAddressOfFunction &&
+ !isSameOrCompatibleFunctionType(
+ Context.getCanonicalType(SpecializationType),
+ Context.getCanonicalType(ArgFunctionType)))
return TDK_MiscellaneousDeductionFailure;
- else if(!InOverloadResolution &&
- !Context.hasSameType(Specialization->getType(), ArgFunctionType))
+
+ if (!IsAddressOfFunction &&
+ !Context.hasSameType(SpecializationType, ArgFunctionType))
return TDK_MiscellaneousDeductionFailure;
}
@@ -3977,16 +4016,22 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate,
/// \param Info the argument will be updated to provide additional information
/// about template argument deduction.
///
+/// \param IsAddressOfFunction If \c true, we are deducing as part of taking
+/// the address of a function template in a context where we do not have a
+/// target type, per [over.over]. If \c false, we are looking up a function
+/// template specialization based on its signature, which only happens when
+/// deducing a function parameter type from an argument that is a template-id
+/// naming a function template specialization.
+///
/// \returns the result of template argument deduction.
-Sema::TemplateDeductionResult
-Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
- TemplateArgumentListInfo *ExplicitTemplateArgs,
- FunctionDecl *&Specialization,
- TemplateDeductionInfo &Info,
- bool InOverloadResolution) {
+Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
+ FunctionTemplateDecl *FunctionTemplate,
+ TemplateArgumentListInfo *ExplicitTemplateArgs,
+ FunctionDecl *&Specialization, TemplateDeductionInfo &Info,
+ bool IsAddressOfFunction) {
return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs,
QualType(), Specialization, Info,
- InOverloadResolution);
+ IsAddressOfFunction);
}
namespace {
diff --git a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
index 105aaa92f91..0b22e3c86dc 100644
--- a/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
+++ b/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++14 -verify %s
-// RUN: %clang_cc1 -std=c++1z -verify %s
+// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s
+// RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s
#if __cplusplus > 201402L
@@ -106,3 +106,47 @@ namespace Builtins {
typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)];
typedef int arr[3];
}
+
+namespace ExplicitInstantiation {
+ template<typename T> void f() noexcept {}
+ template<typename T> struct X { void f() noexcept {} };
+ template void f<int>();
+ template void X<int>::f();
+}
+
+namespace ConversionFunction {
+ struct A { template<typename T> operator T() noexcept; };
+ int a = A().operator int();
+}
+
+using size_t = decltype(sizeof(0));
+
+namespace OperatorDelete {
+ struct W {};
+ struct X {};
+ struct Y {};
+ struct Z {};
+ template<bool N, bool D> struct T {};
+}
+void *operator new(size_t, OperatorDelete::W) noexcept(false);
+void operator delete(void*, OperatorDelete::W) noexcept(false) = delete; // expected-note {{here}}
+void *operator new(size_t, OperatorDelete::X) noexcept(false);
+void operator delete(void*, OperatorDelete::X) noexcept(true) = delete; // expected-note {{here}}
+void *operator new(size_t, OperatorDelete::Y) noexcept(true);
+void operator delete(void*, OperatorDelete::Y) noexcept(false) = delete; // expected-note {{here}}
+void *operator new(size_t, OperatorDelete::Z) noexcept(true);
+void operator delete(void*, OperatorDelete::Z) noexcept(true) = delete; // expected-note {{here}}
+template<bool N, bool D> void *operator new(size_t, OperatorDelete::T<N, D>) noexcept(N);
+template<bool N, bool D> void operator delete(void*, OperatorDelete::T<N, D>) noexcept(D) = delete; // expected-note 4{{here}}
+namespace OperatorDelete {
+ struct A { A(); };
+ A *w = new (W{}) A; // expected-error {{deleted function}}
+ A *x = new (X{}) A; // expected-error {{deleted function}}
+ A *y = new (Y{}) A; // expected-error {{deleted function}}
+ A *z = new (Z{}) A; // expected-error {{deleted function}}
+
+ A *t00 = new (T<false, false>{}) A; // expected-error {{deleted function}}
+ A *t01 = new (T<false, true>{}) A; // expected-error {{deleted function}}
+ A *t10 = new (T<true, false>{}) A; // expected-error {{deleted function}}
+ A *t11 = new (T<true, true>{}) A; // expected-error {{deleted function}}
+}
OpenPOWER on IntegriCloud