diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-10-26 01:05:54 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-10-26 01:05:54 +0000 |
commit | fda59e5851215850f9b9b534bfd8bda579089029 (patch) | |
tree | 5275243be051d4b8a2e4728a161cbea4e948ec66 /clang/lib | |
parent | 7ae21772627a6ce81ad0527640db55daf59bc999 (diff) | |
download | bcm5719-llvm-fda59e5851215850f9b9b534bfd8bda579089029.tar.gz bcm5719-llvm-fda59e5851215850f9b9b534bfd8bda579089029.zip |
Implement name mangling proposal for exception specifications from cxx-abi-dev 2016-10-11.
This has the following ABI impact:
1) Functions whose parameter or return types are non-throwing function pointer
types have different manglings in c++1z mode from prior modes. This is
necessary because c++1z permits overloading on the noexceptness of function
pointer parameter types. A warning is issued for cases that will change
manglings in c++1z mode.
2) Functions whose parameter or return types contain instantiation-dependent
exception specifications change manglings in all modes. This is necessary
to support overloading on / SFINAE in these exception specifications, which
a careful reading of the standard indicates has essentially always been
permitted.
Note that, in order to be affected by these changes, the code in question must
specify an exception specification on a function pointer/reference type that is
written syntactically within the declaration of another function. Such
declarations are very rare, and I have so far been unable to find any code
that would be affected by this. (Note that such things will probably become
more common in C++17, since it's a lot easier to get a noexcept function type
as a function parameter / return type there.)
This change does not affect the set of symbols produced by a build of clang,
libc++, or libc++abi.
llvm-svn: 285150
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 10 | ||||
-rw-r--r-- | clang/lib/AST/ItaniumMangle.cpp | 34 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 2 |
5 files changed, 88 insertions, 3 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a6ac07f25cb..9faded7dc94 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3153,10 +3153,14 @@ static bool isCanonicalExceptionSpecification( // expansions (so we can't tell whether it's non-throwing) and all its // contained types are canonical. if (ESI.Type == EST_Dynamic) { - for (QualType ET : ESI.Exceptions) - if (!ET.isCanonical() || !ET->getAs<PackExpansionType>()) + bool AnyPackExpansions = false; + for (QualType ET : ESI.Exceptions) { + if (!ET.isCanonical()) return false; - return true; + if (ET->getAs<PackExpansionType>()) + AnyPackExpansions = true; + } + return AnyPackExpansions; } // A noexcept(expr) specification is (possibly) canonical if expr is diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 5872e93c131..7f362f6f420 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2245,6 +2245,22 @@ void CXXNameMangler::mangleType(QualType T) { // they aren't written. // - Conversions on non-type template arguments need to be expressed, since // they can affect the mangling of sizeof/alignof. + // + // FIXME: This is wrong when mapping to the canonical type for a dependent + // type discards instantiation-dependent portions of the type, such as for: + // + // template<typename T, int N> void f(T (&)[sizeof(N)]); + // template<typename T> void f(T() throw(typename T::type)); (pre-C++17) + // + // It's also wrong in the opposite direction when instantiation-dependent, + // canonically-equivalent types differ in some irrelevant portion of inner + // type sugar. In such cases, we fail to form correct substitutions, eg: + // + // template<int N> void f(A<sizeof(N)> *, A<sizeof(N)> (*)); + // + // We should instead canonicalize the non-instantiation-dependent parts, + // regardless of whether the type as a whole is dependent or instantiation + // dependent. if (!T->isInstantiationDependentType() || T->isDependentType()) T = T.getCanonicalType(); else { @@ -2547,6 +2563,24 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) { // e.g. "const" in "int (A::*)() const". mangleQualifiers(Qualifiers::fromCVRMask(T->getTypeQuals())); + // Mangle instantiation-dependent exception-specification, if present, + // per cxx-abi-dev proposal on 2016-10-11. + if (T->hasInstantiationDependentExceptionSpec()) { + if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + Out << "nX"; + mangleExpression(T->getNoexceptExpr()); + Out << "E"; + } else { + assert(T->getExceptionSpecType() == EST_Dynamic); + Out << "tw"; + for (auto ExceptTy : T->exceptions()) + mangleType(ExceptTy); + Out << "E"; + } + } else if (T->isNothrow(getASTContext())) { + Out << "nx"; + } + Out << 'F'; // FIXME: We don't have enough information in the AST to produce the 'Y' diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 3e776e30438..444925308ec 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2791,6 +2791,15 @@ bool FunctionProtoType::hasDependentExceptionSpec() const { return false; } +bool FunctionProtoType::hasInstantiationDependentExceptionSpec() const { + if (Expr *NE = getNoexceptExpr()) + return NE->isInstantiationDependent(); + for (QualType ET : exceptions()) + if (ET->isInstantiationDependentType()) + return true; + return false; +} + FunctionProtoType::NoexceptResult FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { ExceptionSpecificationType est = getExceptionSpecType(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aba171b9688..e9e0f5e214d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8996,6 +8996,42 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, !R->isObjCObjectPointerType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } + + // C++1z [dcl.fct]p6: + // [...] whether the function has a non-throwing exception-specification + // [is] part of the function type + // + // This results in an ABI break between C++14 and C++17 for functions whose + // declared type includes an exception-specification in a parameter or + // return type. (Exception specifications on the function itself are OK in + // most cases, and exception specifications are not permitted in most other + // contexts where they could make it into a mangling.) + if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) { + auto HasNoexcept = [&](QualType T) -> bool { + // Strip off declarator chunks that could be between us and a function + // type. We don't need to look far, exception specifications are very + // restricted prior to C++17. + if (auto *RT = T->getAs<ReferenceType>()) + T = RT->getPointeeType(); + else if (T->isAnyPointerType()) + T = T->getPointeeType(); + else if (auto *MPT = T->getAs<MemberPointerType>()) + T = MPT->getPointeeType(); + if (auto *FPT = T->getAs<FunctionProtoType>()) + if (FPT->isNothrow(Context)) + return true; + return false; + }; + + auto *FPT = NewFD->getType()->castAs<FunctionProtoType>(); + bool AnyNoexcept = HasNoexcept(FPT->getReturnType()); + for (QualType T : FPT->param_types()) + AnyNoexcept |= HasNoexcept(T); + if (AnyNoexcept) + Diag(NewFD->getLocation(), + diag::warn_cxx1z_compat_exception_spec_in_signature) + << NewFD; + } } return Redeclaration; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index a17bcd3b9d9..a461b33c4d2 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -5119,6 +5119,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec( } ESI.Exceptions = Exceptions; + if (ESI.Exceptions.empty()) + ESI.Type = EST_DynamicNone; return false; } |