Author: rsmith Date: Thu Sep 29 17:49:46 2016 New Revision: 282800 URL: http://llvm.org/viewvc/llvm-project?rev=282800&view=rev Log: P0035R4: add std::align_val_t overloads of operator new/delete in C++17 mode.
Added: cfe/trunk/test/PCH/cxx1z-aligned-alloc.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/AST/DeclCXX.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaExprCXX.cpp cfe/trunk/lib/Serialization/ASTReader.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/test/CXX/drs/dr5xx.cpp Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Thu Sep 29 17:49:46 2016 @@ -721,6 +721,10 @@ public: /// standard library. LazyDeclPtr StdBadAlloc; + /// \brief The C++ "std::align_val_t" enum class, which is defined by the C++ + /// standard library. + LazyDeclPtr StdAlignValT; + /// \brief The C++ "std::initializer_list" template, which is defined in /// \<initializer_list>. ClassTemplateDecl *StdInitializerList; @@ -4237,6 +4241,7 @@ public: NamespaceDecl *getOrCreateStdNamespace(); CXXRecordDecl *getStdBadAlloc() const; + EnumDecl *getStdAlignValT() const; /// \brief Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. @@ -4838,8 +4843,7 @@ public: bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Param1, - QualType Param2 = QualType()); + ArrayRef<QualType> Params); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, Modified: cfe/trunk/lib/AST/DeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp (original) +++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Sep 29 17:49:46 2016 @@ -1577,7 +1577,7 @@ bool CXXMethodDecl::isUsualDeallocationF // deallocation function. [...] if (getNumParams() == 1) return true; - + // C++ [basic.stc.dynamic.deallocation]p2: // [...] If class T does not declare such an operator delete but does // declare a member deallocation function named operator delete with Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Sep 29 17:49:46 2016 @@ -12535,6 +12535,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; + bool isStdAlignValT = false; RedeclarationKind Redecl = ForRedeclaration; if (TUK == TUK_Friend || TUK == TUK_Reference) @@ -12689,15 +12690,20 @@ Decl *Sema::ActOnTag(Scope *S, unsigned } if (getLangOpts().CPlusPlus && Name && DC && StdNamespace && - DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) { - // This is a declaration of or a reference to "std::bad_alloc". - isStdBadAlloc = true; - - if (Previous.empty() && StdBadAlloc) { - // std::bad_alloc has been implicitly declared (but made invisible to - // name lookup). Fill in this implicit declaration as the previous + DC->Equals(getStdNamespace())) { + if (Name->isStr("bad_alloc")) { + // This is a declaration of or a reference to "std::bad_alloc". + isStdBadAlloc = true; + + // If std::bad_alloc has been implicitly declared (but made invisible to + // name lookup), fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. - Previous.addDecl(getStdBadAlloc()); + if (Previous.empty() && StdBadAlloc) + Previous.addDecl(getStdBadAlloc()); + } else if (Name->isStr("align_val_t")) { + isStdAlignValT = true; + if (Previous.empty() && StdAlignValT) + Previous.addDecl(getStdAlignValT()); } } @@ -13089,6 +13095,10 @@ CreateNewDecl: New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); + + if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit())) + StdAlignValT = cast<EnumDecl>(New); + // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Sep 29 17:49:46 2016 @@ -8266,6 +8266,10 @@ CXXRecordDecl *Sema::getStdBadAlloc() co StdBadAlloc.get(Context.getExternalSource())); } +EnumDecl *Sema::getStdAlignValT() const { + return cast_or_null<EnumDecl>(StdAlignValT.get(Context.getExternalSource())); +} + NamespaceDecl *Sema::getStdNamespace() const { return cast_or_null<NamespaceDecl>( StdNamespace.get(Context.getExternalSource())); Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Thu Sep 29 17:49:46 2016 @@ -2340,41 +2340,61 @@ void Sema::DeclareGlobalNewDelete() { nullptr); getStdBadAlloc()->setImplicit(true); } + if (!StdAlignValT && getLangOpts().CPlusPlus1z) { + // The "std::align_val_t" enum class has not yet been declared, so build it + // implicitly. + auto *AlignValT = EnumDecl::Create( + Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), + &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); + AlignValT->setIntegerType(Context.getSizeType()); + AlignValT->setPromotionType(Context.getSizeType()); + AlignValT->setImplicit(true); + StdAlignValT = AlignValT; + } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_New), - VoidPtr, SizeT, QualType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_New), - VoidPtr, SizeT, QualType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Delete), - Context.VoidTy, VoidPtr); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), - Context.VoidTy, VoidPtr); - if (getLangOpts().SizedDeallocation) { - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Delete), - Context.VoidTy, VoidPtr, Context.getSizeType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), - Context.VoidTy, VoidPtr, Context.getSizeType()); - } + auto DeclareGlobalAllocationFunctions = [&](OverloadedOperatorKind Kind, + QualType Return, QualType Param) { + llvm::SmallVector<QualType, 3> Params; + Params.push_back(Param); + + // Create up to four variants of the function (sized/aligned). + bool HasSizedVariant = getLangOpts().SizedDeallocation && + (Kind == OO_Delete || Kind == OO_Array_Delete); + bool HasAlignedVariant = getLangOpts().CPlusPlus1z; + for (int Sized = 0; Sized <= HasSizedVariant; ++Sized) { + if (Sized) + Params.push_back(SizeT); + + for (int Aligned = 0; Aligned <= HasAlignedVariant; ++Aligned) { + if (Aligned) + Params.push_back(Context.getTypeDeclType(getStdAlignValT())); + + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(Kind), Return, Params); + + if (Aligned) + Params.pop_back(); + } + } + }; + + DeclareGlobalAllocationFunctions(OO_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); + DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); } /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Param1, QualType Param2) { + ArrayRef<QualType> Params) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); - unsigned NumParams = Param2.isNull() ? 1 : 2; // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); @@ -2383,18 +2403,12 @@ void Sema::DeclareGlobalAllocationFuncti // Only look at non-template functions, as it is the predefined, // non-templated allocation function we are trying to declare here. if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) { - if (Func->getNumParams() == NumParams) { - QualType InitialParam1Type = - Context.getCanonicalType(Func->getParamDecl(0) - ->getType().getUnqualifiedType()); - QualType InitialParam2Type = - NumParams == 2 - ? Context.getCanonicalType(Func->getParamDecl(1) - ->getType().getUnqualifiedType()) - : QualType(); - // FIXME: Do we need to check for default arguments here? - if (InitialParam1Type == Param1 && - (NumParams == 1 || InitialParam2Type == Param2)) { + if (Func->getNumParams() == Params.size()) { + llvm::SmallVector<QualType, 3> FuncParams; + for (auto *P : Func->parameters()) + FuncParams.push_back( + Context.getCanonicalType(P->getType().getUnqualifiedType())); + if (llvm::makeArrayRef(FuncParams) == Params) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. @@ -2423,10 +2437,7 @@ void Sema::DeclareGlobalAllocationFuncti getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } - QualType Params[] = { Param1, Param2 }; - - QualType FnType = Context.getFunctionType( - Return, llvm::makeArrayRef(Params, NumParams), EPI); + QualType FnType = Context.getFunctionType(Return, Params, EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, @@ -2437,15 +2448,14 @@ void Sema::DeclareGlobalAllocationFuncti Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, VisibilityAttr::Default)); - ParmVarDecl *ParamDecls[2]; - for (unsigned I = 0; I != NumParams; ++I) { - ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - SourceLocation(), nullptr, - Params[I], /*TInfo=*/nullptr, - SC_None, nullptr); - ParamDecls[I]->setImplicit(); + llvm::SmallVector<ParmVarDecl*, 3> ParamDecls; + for (QualType T : Params) { + ParamDecls.push_back( + ParmVarDecl::Create(Context, Alloc, SourceLocation(), SourceLocation(), + nullptr, T, /*TInfo=*/nullptr, SC_None, nullptr)); + ParamDecls.back()->setImplicit(); } - Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams)); + Alloc->setParams(ParamDecls); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); Modified: cfe/trunk/lib/Serialization/ASTReader.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReader.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReader.cpp Thu Sep 29 17:49:46 2016 @@ -3045,7 +3045,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, u break; case SEMA_DECL_REFS: - if (Record.size() != 2) { + if (Record.size() != 3) { Error("Invalid SEMA_DECL_REFS block"); return Failure; } @@ -7104,12 +7104,14 @@ void ASTReader::UpdateSema() { // Load the offsets of the declarations that Sema references. // They will be lazily deserialized when needed. if (!SemaDeclRefs.empty()) { - assert(SemaDeclRefs.size() % 2 == 0); - for (unsigned I = 0; I != SemaDeclRefs.size(); I += 2) { + assert(SemaDeclRefs.size() % 3 == 0); + for (unsigned I = 0; I != SemaDeclRefs.size(); I += 3) { if (!SemaObj->StdNamespace) SemaObj->StdNamespace = SemaDeclRefs[I]; if (!SemaObj->StdBadAlloc) SemaObj->StdBadAlloc = SemaDeclRefs[I+1]; + if (!SemaObj->StdAlignValT) + SemaObj->StdAlignValT = SemaDeclRefs[I+2]; } SemaDeclRefs.clear(); } Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Thu Sep 29 17:49:46 2016 @@ -4363,9 +4363,10 @@ uint64_t ASTWriter::WriteASTCore(Sema &S // Build a record containing some declaration references. RecordData SemaDeclRefs; - if (SemaRef.StdNamespace || SemaRef.StdBadAlloc) { + if (SemaRef.StdNamespace || SemaRef.StdBadAlloc || SemaRef.StdAlignValT) { AddDeclRef(SemaRef.getStdNamespace(), SemaDeclRefs); AddDeclRef(SemaRef.getStdBadAlloc(), SemaDeclRefs); + AddDeclRef(SemaRef.getStdAlignValT(), SemaDeclRefs); } RecordData CUDASpecialDeclRefs; Modified: cfe/trunk/test/CXX/drs/dr5xx.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr5xx.cpp?rev=282800&r1=282799&r2=282800&view=diff ============================================================================== --- cfe/trunk/test/CXX/drs/dr5xx.cpp (original) +++ cfe/trunk/test/CXX/drs/dr5xx.cpp Thu Sep 29 17:49:46 2016 @@ -8,6 +8,12 @@ // with -verify. __extension__ typedef __SIZE_TYPE__ size_t; void *operator new(size_t); // expected-error 0-1{{missing exception spec}} expected-note{{candidate}} +#if __cplusplus > 201402L +namespace std { + enum class align_val_t : size_t {}; +} +void *operator new(size_t, std::align_val_t); // expected-note{{candidate}} +#endif namespace dr500 { // dr500: dup 372 class D; Added: cfe/trunk/test/PCH/cxx1z-aligned-alloc.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1z-aligned-alloc.cpp?rev=282800&view=auto ============================================================================== --- cfe/trunk/test/PCH/cxx1z-aligned-alloc.cpp (added) +++ cfe/trunk/test/PCH/cxx1z-aligned-alloc.cpp Thu Sep 29 17:49:46 2016 @@ -0,0 +1,35 @@ +// No PCH: +// RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -include %s -verify %s +// +// With PCH: +// RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -emit-pch %s -o %t +// RUN: %clang_cc1 -pedantic -fsized-deallocation -std=c++1z -include-pch %t -verify %s + +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +using size_t = decltype(sizeof(0)); + +// Call the overaligned form of 'operator new'. +struct alignas(256) Q { int n; }; +void *f() { return new Q; } + +// Extract the std::align_val_t type from the implicit declaration of operator delete. +template<typename AlignValT> +AlignValT extract(void (*)(void*, size_t, AlignValT)); +using T = decltype(extract(&operator delete)); + +#else + +// ok, calls aligned allocation via placement syntax +void *q = new (T{16}) Q; + +namespace std { + enum class align_val_t : size_t {}; +} + +using T = std::align_val_t; // ok, same type + +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits