Author: rsmith Date: Mon Oct 31 20:34:46 2016 New Revision: 285664 URL: http://llvm.org/viewvc/llvm-project?rev=285664&view=rev Log: Implement ABI proposal for throwing noexcept function pointers, per discussion on cxx-abi-dev (thread starting 2016-10-11). This is currently hidden behind a cc1-only -m flag, pending discussion of how best to deal with language changes that require use of new symbols from the ABI library.
Added: cfe/trunk/test/CodeGenCXX/rtti-qualfn.cpp Modified: cfe/trunk/include/clang/Driver/CC1Options.td cfe/trunk/include/clang/Frontend/CodeGenOptions.def cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp cfe/trunk/lib/Frontend/CompilerInvocation.cpp cfe/trunk/www/cxx_status.html Modified: cfe/trunk/include/clang/Driver/CC1Options.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=285664&r1=285663&r2=285664&view=diff ============================================================================== --- cfe/trunk/include/clang/Driver/CC1Options.td (original) +++ cfe/trunk/include/clang/Driver/CC1Options.td Mon Oct 31 20:34:46 2016 @@ -251,6 +251,8 @@ def munwind_tables : Flag<["-"], "munwin HelpText<"Generate unwinding tables for all functions">; def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">, HelpText<"Emit complete constructors and destructors as aliases when possible">; +def mqualified_function_type_info : Flag<["-"], "mqualified-function-type-info">, + HelpText<"Emit __qualified_function_type_info for qualified function types">; def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">, HelpText<"Link the given bitcode file before performing optimizations.">; def mlink_cuda_bitcode : Separate<["-"], "mlink-cuda-bitcode">, Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=285664&r1=285663&r2=285664&view=diff ============================================================================== --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original) +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Mon Oct 31 20:34:46 2016 @@ -133,6 +133,7 @@ CODEGENOPT(DumpCoverageMapping , 1, 0) / /// If -fpcc-struct-return or -freg-struct-return is specified. ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Default) +CODEGENOPT(QualifiedFunctionTypeInfo, 1, 0) ///< Use __qualified_function_type_info. CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions. CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled. CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA. Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=285664&r1=285663&r2=285664&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original) +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Mon Oct 31 20:34:46 2016 @@ -46,6 +46,7 @@ protected: bool UseARMMethodPtrABI; bool UseARMGuardVarABI; bool Use32BitVTableOffsetABI; + bool UseQualifiedFunctionTypeInfoABI; ItaniumMangleContext &getMangleContext() { return cast<ItaniumMangleContext>(CodeGen::CGCXXABI::getMangleContext()); @@ -57,7 +58,8 @@ public: bool UseARMGuardVarABI = false) : CGCXXABI(CGM), UseARMMethodPtrABI(UseARMMethodPtrABI), UseARMGuardVarABI(UseARMGuardVarABI), - Use32BitVTableOffsetABI(false) { } + Use32BitVTableOffsetABI(false), + UseQualifiedFunctionTypeInfoABI(CGM.getCodeGenOpts().QualifiedFunctionTypeInfo) { } bool classifyReturnType(CGFunctionInfo &FI) const override; @@ -2427,6 +2429,9 @@ class ItaniumRTTIBuilder { /// descriptor of the given type. llvm::Constant *GetAddrOfExternalRTTIDescriptor(QualType Ty); + /// Determine whether FnTy should be emitted as a qualified function type. + bool EmitAsQualifiedFunctionType(const FunctionType *FnTy); + /// BuildVTablePointer - Build the vtable pointer for the given type. void BuildVTablePointer(const Type *Ty); @@ -2439,6 +2444,10 @@ class ItaniumRTTIBuilder { /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c. void BuildVMIClassTypeInfo(const CXXRecordDecl *RD); + /// Build an abi::__qualified_function_type_info struct, used for function + /// types with various kinds of qualifiers. + void BuildQualifiedFunctionTypeInfo(const FunctionType *FnTy); + /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, used /// for pointer types. void BuildPointerTypeInfo(QualType PointeeTy); @@ -2455,6 +2464,27 @@ public: ItaniumRTTIBuilder(const ItaniumCXXABI &ABI) : CGM(ABI.CGM), VMContext(CGM.getModule().getContext()), CXXABI(ABI) {} + // Function type info flags. + enum { + /// Qualifiers for 'this' pointer of member function type. + //@{ + QFTI_Const = 0x1, + QFTI_Volatile = 0x2, + QFTI_Restrict = 0x4, + QFTI_LValRef = 0x8, + QFTI_RValRef = 0x10, + //@} + + /// Noexcept function qualifier (C++17 onwards). + QFTI_Noexcept = 0x20, + + // Transaction-safe function qualifier (Transactional Memory TS). + //QFTI_TxSafe = 0x40, + + /// Noreturn function type qualifier (GNU/Clang extension). + QFTI_Noreturn = 0x80 + }; + // Pointer type info flags. enum { /// PTI_Const - Type has const qualifier. @@ -2806,8 +2836,12 @@ void ItaniumRTTIBuilder::BuildVTablePoin case Type::FunctionNoProto: case Type::FunctionProto: - // abi::__function_type_info. - VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; + if (EmitAsQualifiedFunctionType(cast<FunctionType>(Ty))) + // abi::__qualified_function_type_info. + VTableName = "_ZTVN10__cxxabiv130__qualified_function_type_infoE"; + else + // abi::__function_type_info. + VTableName = "_ZTVN10__cxxabiv120__function_type_infoE"; break; case Type::Enum: @@ -3021,10 +3055,15 @@ llvm::Constant *ItaniumRTTIBuilder::Buil break; case Type::FunctionNoProto: - case Type::FunctionProto: + case Type::FunctionProto: { + auto *FnTy = cast<FunctionType>(Ty); // Itanium C++ ABI 2.9.5p5: // abi::__function_type_info adds no data members to std::type_info. + if (EmitAsQualifiedFunctionType(FnTy)) + // abi::__qualified_type_info adds a base function type and qualifiers. + BuildQualifiedFunctionTypeInfo(FnTy); break; + } case Type::Enum: // Itanium C++ ABI 2.9.5p5: @@ -3319,6 +3358,72 @@ void ItaniumRTTIBuilder::BuildVMIClassTy } } +bool ItaniumRTTIBuilder::EmitAsQualifiedFunctionType(const FunctionType *FnTy) { + if (!CXXABI.UseQualifiedFunctionTypeInfoABI) + return false; + + auto *FPT = dyn_cast<FunctionProtoType>(FnTy); + if (!FPT) + return false; + return FPT->getTypeQuals() || FPT->getRefQualifier() != RQ_None || + FPT->isNothrow(CXXABI.getContext()) || FPT->getNoReturnAttr(); +} + +void ItaniumRTTIBuilder::BuildQualifiedFunctionTypeInfo( + const FunctionType *FnTy) { + unsigned int Qualifiers = 0; + + auto ExtInfo = FnTy->getExtInfo(); + if (ExtInfo.getNoReturn()) { + Qualifiers |= QFTI_Noreturn; + ExtInfo = ExtInfo.withNoReturn(false); + } + + QualType BaseType; + if (auto *FPT = dyn_cast<FunctionProtoType>(FnTy)) { + auto EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = ExtInfo; + + if (EPI.TypeQuals & Qualifiers::Const) + Qualifiers |= QFTI_Const; + if (EPI.TypeQuals & Qualifiers::Volatile) + Qualifiers |= QFTI_Volatile; + if (EPI.TypeQuals & Qualifiers::Restrict) + Qualifiers |= QFTI_Restrict; + EPI.TypeQuals = 0; + + if (EPI.RefQualifier == RQ_LValue) + Qualifiers |= QFTI_LValRef; + else if (EPI.RefQualifier == RQ_RValue) + Qualifiers |= QFTI_RValRef; + EPI.RefQualifier = RQ_None; + + if (EPI.ExceptionSpec.Type == EST_BasicNoexcept) + Qualifiers |= QFTI_Noexcept; + else + assert(EPI.ExceptionSpec.Type == EST_None && + "unexpected canonical non-dependent exception spec"); + EPI.ExceptionSpec.Type = EST_None; + + BaseType = CXXABI.getContext().getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI); + } else { + BaseType = + QualType(CXXABI.getContext().adjustFunctionType(FnTy, ExtInfo), 0); + } + + assert(Qualifiers && "should not have created qualified type info"); + + // __base_type is a pointer to the std::type_info derivation for the + // unqualified version of the function type. + Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(BaseType)); + + // __qualifiers is a flag word describing the qualifiers of the function type. + llvm::Type *UnsignedIntLTy = + CGM.getTypes().ConvertType(CGM.getContext().UnsignedIntTy); + Fields.push_back(llvm::ConstantInt::get(UnsignedIntLTy, Qualifiers)); +} + /// BuildPointerTypeInfo - Build an abi::__pointer_type_info struct, /// used for pointer types. void ItaniumRTTIBuilder::BuildPointerTypeInfo(QualType PointeeTy) { Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=285664&r1=285663&r2=285664&view=diff ============================================================================== --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original) +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Mon Oct 31 20:34:46 2016 @@ -553,6 +553,7 @@ static bool ParseCodeGenArgs(CodeGenOpti Opts.ObjCAutoRefCountExceptions = Args.hasArg(OPT_fobjc_arc_exceptions); Opts.CXAAtExit = !Args.hasArg(OPT_fno_use_cxa_atexit); Opts.CXXCtorDtorAliases = Args.hasArg(OPT_mconstructor_aliases); + Opts.QualifiedFunctionTypeInfo = Args.hasArg(OPT_mqualified_function_type_info); Opts.CodeModel = getCodeModel(Args, Diags); Opts.DebugPass = Args.getLastArgValue(OPT_mdebug_pass); Opts.DisableFPElim = Added: cfe/trunk/test/CodeGenCXX/rtti-qualfn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/rtti-qualfn.cpp?rev=285664&view=auto ============================================================================== --- cfe/trunk/test/CodeGenCXX/rtti-qualfn.cpp (added) +++ cfe/trunk/test/CodeGenCXX/rtti-qualfn.cpp Mon Oct 31 20:34:46 2016 @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c++1z -mqualified-function-type-info -I%S %s -triple x86_64-linux-gnu -emit-llvm -o - -fcxx-exceptions | FileCheck %s + +#include "typeinfo" + +struct A {}; + +// CHECK-DAG: @_ZTIKFvvE = [[QFTI:linkonce_odr constant { i8\*, i8\*, i8\*, i32 } { i8\* bitcast \(i8\*\* getelementptr inbounds \(i8\*, i8\*\* @_ZTVN10__cxxabiv130__qualified_function_type_infoE, i64 2\) to i8\*\),]] i8* getelementptr inbounds ([6 x i8], [6 x i8]* @_ZTSKFvvE, i32 0, i32 0), i8* bitcast ({ i8*, i8* }* @_ZTIFvvE to i8*), i32 1 }, comdat +// CHECK-DAG: @_ZTIM1AKFvvE = [[PMFTI:linkonce_odr constant { i8\*, i8\*, i32, i8\*, i8\* } { i8\* bitcast \(i8\*\* getelementptr inbounds \(i8\*, i8\*\* @_ZTVN10__cxxabiv129__pointer_to_member_type_infoE, i64 2\) to i8\*\),]] i8* getelementptr inbounds ([9 x i8], [9 x i8]* @_ZTSM1AKFvvE, i32 0, i32 0), i32 0, i8* bitcast ({ i8*, i8*, i8*, i32 }* @_ZTIKFvvE to i8*), i8* bitcast ({ i8*, i8* }* @_ZTI1A to i8*) }, comdat +auto &ti_const = typeid(void (A::*)() const); + +// CHECK-DAG: @_ZTIVFvvE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 2 }, comdat +// CHECK-DAG: @_ZTIM1AVFvvE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIVFvvE +auto &ti_volatile = typeid(void (A::*)() volatile); + +// CHECK-DAG: @_ZTIrFvvE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 4 }, comdat +// CHECK-DAG: @_ZTIM1ArFvvE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIrFvvE +auto &ti_restrict = typeid(void (A::*)() __restrict); + +// CHECK-DAG: @_ZTIFvvRE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 8 }, comdat +// CHECK-DAG: @_ZTIM1AFvvRE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIFvvRE +auto &ti_lref = typeid(void (A::*)() &); + +// CHECK-DAG: @_ZTIFvvOE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 16 }, comdat +// CHECK-DAG: @_ZTIM1AFvvOE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIFvvOE +auto &ti_rref = typeid(void (A::*)() &&); + +// CHECK-DAG: @_ZTInxFvvE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 32 }, comdat +// CHECK-DAG: @_ZTIM1AnxFvvE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTInxFvvE +auto &ti_noexcept = typeid(void (A::*)() noexcept); + +//auto &ti_txsafe = typeid(void (A::*)() transaction_safe); + +// FIXME: Produce the typeinfo for a noreturn function type here? +// CHECK-DAG: @_ZTIM1AFvvE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIFvvE +auto &ti_noreturn = typeid(void __attribute__((noreturn)) (A::*)()); + +// CHECK-DAG: @_ZTIrVKnxFvvRE = [[QFTI]] {{.*}} @_ZTIFvvE {{.*}}, i32 47 }, comdat +// CHECK-DAG: @_ZTIM1ArVKnxFvvRE = [[PMFTI]] {{.*}}), i32 0, {{.*}} @_ZTIrVKnxFvvRE +auto &ti_rainbow = typeid(void (A::*)() const volatile __restrict & noexcept); + +// CHECK-LABEL: define void @_Z1fv( +__attribute__((noreturn)) void f() noexcept { + // CHECK: call void @__cxa_throw({{.*}}@_ZTIPnxFvvE + throw f; +} + +// CHECK-LABEL: define void @_Z1gM1AnxFvvE( +void g(__attribute__((noreturn)) void (A::*p)() noexcept) { + // CHECK: call void @__cxa_throw({{.*}}@_ZTIM1AnxFvvE + throw p; +} Modified: cfe/trunk/www/cxx_status.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=285664&r1=285663&r2=285664&view=diff ============================================================================== --- cfe/trunk/www/cxx_status.html (original) +++ cfe/trunk/www/cxx_status.html Mon Oct 31 20:34:46 2016 @@ -612,9 +612,7 @@ as the draft C++1z standard evolves. <tr> <td>Make exception specifications part of the type system</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0012r1.html">P0012R1</a></td> - <td class="partial" align="center">Partial</td> - <!-- We don't correctly support throwing noexcept function types and - catching as non-noexcept yet. --> + <td class="svn" align="center">SVN <a href="#p0012">(9)</a></td> </tr> <tr> <td><tt>__has_include</tt> in preprocessor conditionals</td> @@ -624,7 +622,7 @@ as the draft C++1z standard evolves. <tr> <td>New specification for inheriting constructors (<a href="cxx_dr_status.html#1941">DR1941</a> et al)</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html">P0136R1</a></td> - <td class="full" align="center">Clang 3.9 <a href="#p0136">(9)</a></td> + <td class="full" align="center">Clang 3.9 <a href="#p0136">(10)</a></td> </tr> <!-- Jacksonville papers --> <tr> @@ -701,7 +699,7 @@ as the draft C++1z standard evolves. <tr> <td rowspan=2>Stricter expression evaluation order</td> <td><a href="http://wg21.link/p0145r3">P0145R3</a></td> - <td class="svn" align="center" rowspan=2>SVN <a href="#p0145">(10)</a></td> + <td class="svn" align="center" rowspan=2>SVN <a href="#p0145">(11)</a></td> </tr> <tr> <td><a href="http://wg21.link/p0400r0">P0400R0</a></td> @@ -741,10 +739,18 @@ all language versions that allow type de (per the request of the C++ committee). In Clang 3.7, a warning is emitted for all cases that would change meaning. </span><br> -<span id="p0136">(9): This is the resolution to a Defect Report, so is applied +<span id="p0012">(9): Support for throwing a noexcept function pointer and +catching it as a non-noexcept function pointer requires an ABI library with +C++17 support. Currently, only libc++abi 4.0 provides this support, so this +portion of the feature is disabled by default. If you are using a sufficiently +recent ABI library, you can enable support for this feature with the +<code>-Xclang -mqualified-function-type-info</code> flag. This flag is likely +to be removed or replaced in future Clang releases. +</span><br> +<span id="p0136">(10): This is the resolution to a Defect Report, so is applied to all language versions supporting inheriting constructors. </span><br> -<span id="p0145">(10): Under the MS ABI, function parameters are destroyed from +<span id="p0145">(11): Under the MS ABI, function parameters are destroyed from left to right in the callee. As a result, function parameters in calls to <tt>operator<<</tt>, <tt>operator>></tt>, <tt>operator->*</tt>, <tt>operator&&</tt>, <tt>operator||</tt>, and <tt>operator,</tt> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits