From 583cd05ce39d3342e4da7887fd5fbd828507c043 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 2 Oct 2019 18:19:02 +0000 Subject: [PATCH 01/33] [OPENMP50]Add parsing/sema analysis for declare variant score. Context selectors may include optional score clause in format `score():`, where `` must be a constant integer expression. Added parsing/sema analysis only. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373502 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 15 +++++++++++++ include/clang/Sema/Sema.h | 7 ++++-- lib/Parse/ParseOpenMP.cpp | 26 +++++++++++++++++++++++ lib/Sema/SemaOpenMP.cpp | 17 ++++++++++++++- lib/Sema/SemaTemplateInstantiateDecl.cpp | 9 ++++++-- test/OpenMP/declare_variant_ast_print.c | 2 ++ test/OpenMP/declare_variant_ast_print.cpp | 21 +++++++++++------- test/OpenMP/declare_variant_messages.c | 5 +++++ test/OpenMP/declare_variant_messages.cpp | 14 ++++++++++-- 9 files changed, 101 insertions(+), 15 deletions(-) diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 14834a1f5414..283d0f32007a 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -3290,12 +3290,19 @@ def OMPDeclareVariant : InheritableAttr { let Documentation = [OMPDeclareVariantDocs]; let Args = [ ExprArgument<"VariantFuncRef">, + ExprArgument<"Score">, EnumArgument<"CtxSelectorSet", "CtxSelectorSetType", [ "", "implementation" ], [ "CtxSetUnknown", "CtxSetImplementation" ]>, + EnumArgument<"CtxScore", "ScoreType", + [ "", "score" + ], + [ + "ScoreUnknown", "ScoreSpecified" + ]>, EnumArgument<"CtxSelector", "CtxSelectorType", [ "", "vendor" ], @@ -3305,6 +3312,13 @@ def OMPDeclareVariant : InheritableAttr { StringArgument<"ImplVendor", 1> ]; let AdditionalMembers = [{ + void printScore(raw_ostream & OS, const PrintingPolicy &Policy) const { + if (const Expr *E = getScore()) { + OS << "score("; + E->printPretty(OS, nullptr, Policy); + OS << "):"; + } + } void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy) const { assert(getCtxSelectorSet() != CtxSetUnknown && @@ -3322,6 +3336,7 @@ def OMPDeclareVariant : InheritableAttr { switch (getCtxSelector()) { case CtxVendor: OS << "vendor("; + printScore(OS, Policy); OS << getImplVendor(); OS << ")"; break; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1c587cf5c1b5..1e763bdf8d97 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -9109,11 +9109,14 @@ class Sema { OMPDeclareVariantAttr::CtxSelectorType Ctx = OMPDeclareVariantAttr::CtxUnknown; StringRef ImplVendor; + ExprResult CtxScore; explicit OpenMPDeclareVariantCtsSelectorData() = default; explicit OpenMPDeclareVariantCtsSelectorData( OMPDeclareVariantAttr::CtxSelectorSetType CtxSet, - OMPDeclareVariantAttr::CtxSelectorType Ctx, StringRef ImplVendor) - : CtxSet(CtxSet), Ctx(Ctx), ImplVendor(ImplVendor) {} + OMPDeclareVariantAttr::CtxSelectorType Ctx, StringRef ImplVendor, + ExprResult CtxScore) + : CtxSet(CtxSet), Ctx(Ctx), ImplVendor(ImplVendor), CtxScore(CtxScore) { + } }; /// Checks if the variant/multiversion functions are compatible. diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 46c823816830..c7143fd41041 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -786,6 +786,31 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, LinModifiers, Steps, SourceRange(Loc, EndLoc)); } +/// Parse optional 'score' '(' ')' ':'. +static ExprResult parseContextScore(Parser &P) { + ExprResult ScoreExpr; + SmallString<16> Buffer; + StringRef SelectorName = + P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); + OMPDeclareVariantAttr::ScoreType ScoreKind = + OMPDeclareVariantAttr::ScoreUnknown; + (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind); + if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown) + return ScoreExpr; + assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified && + "Expected \"score\" clause."); + (void)P.ConsumeToken(); + SourceLocation RLoc; + ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc); + // Parse ':' + if (P.getCurToken().is(tok::colon)) + (void)P.ConsumeAnyToken(); + else + P.Diag(P.getCurToken(), diag::warn_pragma_expected_colon) + << "context selector score clause"; + return ScoreExpr; +} + /// Parse context selector for 'implementation' selector set: /// 'vendor' '(' ')' static void @@ -815,6 +840,7 @@ parseImplementationSelector(Parser &P, BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); (void)T.expectAndConsume(diag::err_expected_lparen_after, CtxSelectorName.data()); + Data.CtxScore = parseContextScore(P); // Parse . StringRef VendorName; if (Tok.is(tok::identifier)) { diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 42e1755b5862..2b659f7f11f9 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -5112,8 +5112,23 @@ void Sema::ActOnOpenMPDeclareVariantDirective( if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) return; + Expr *Score = nullptr; + OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown; + if (Data.CtxScore.isUsable()) { + ST = OMPDeclareVariantAttr::ScoreSpecified; + Score = Data.CtxScore.get(); + if (!Score->isTypeDependent() && !Score->isValueDependent() && + !Score->isInstantiationDependent() && + !Score->containsUnexpandedParameterPack()) { + llvm::APSInt Result; + ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result); + if (ICE.isInvalid()) + return; + } + } auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantRef, Data.CtxSet, Data.Ctx, Data.ImplVendor, SR); + Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx, Data.ImplVendor, + SR); FD->addAttr(NewAttr); } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index f6cf3696e1fd..881b4fd992e1 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -388,6 +388,10 @@ static void instantiateOMPDeclareVariantAttr( if (Expr *E = Attr.getVariantFuncRef()) VariantFuncRef = Subst(E); + ExprResult Score; + if (Expr *E = Attr.getScore()) + Score = Subst(E); + // Check function/variant ref. Optional> DeclVarData = S.checkOpenMPDeclareVariantFunction( @@ -395,8 +399,9 @@ static void instantiateOMPDeclareVariantAttr( if (!DeclVarData) return; // Instantiate the attribute. - Sema::OpenMPDeclareVariantCtsSelectorData Data( - Attr.getCtxSelectorSet(), Attr.getCtxSelector(), Attr.getImplVendor()); + Sema::OpenMPDeclareVariantCtsSelectorData Data(Attr.getCtxSelectorSet(), + Attr.getCtxSelector(), + Attr.getImplVendor(), Score); S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, DeclVarData.getValue().second, Attr.getRange(), Data); diff --git a/test/OpenMP/declare_variant_ast_print.c b/test/OpenMP/declare_variant_ast_print.c index 4c91e2e54184..ad1ef91eca14 100644 --- a/test/OpenMP/declare_variant_ast_print.c +++ b/test/OpenMP/declare_variant_ast_print.c @@ -10,9 +10,11 @@ int foo(void); #pragma omp declare variant(foo) match(xxx={vvv}) #pragma omp declare variant(foo) match(implementation={vendor(ibm)}, implementation={vendor(llvm)}) #pragma omp declare variant(foo) match(implementation={vendor(unknown)}) +#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm)}) int bar(void); // CHECK: int foo(); +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):ibm)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(unknown)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(ibm)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(llvm)}) diff --git a/test/OpenMP/declare_variant_ast_print.cpp b/test/OpenMP/declare_variant_ast_print.cpp index 1760751c8034..77f03f518552 100644 --- a/test/OpenMP/declare_variant_ast_print.cpp +++ b/test/OpenMP/declare_variant_ast_print.cpp @@ -17,7 +17,8 @@ T foofoo() { return T(); } // CHECK-NEXT: return int(); // CHECK-NEXT: } -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(5):ibm)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(ibm)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(llvm)}) // CHECK-NEXT: int bar(); @@ -25,12 +26,14 @@ T foofoo() { return T(); } #pragma omp declare variant(foofoo ) match(xxx = {vvv}) #pragma omp declare variant(foofoo ) match(implementation={vendor(ibm)}, implementation={vendor(llvm)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm)}) int bar(); -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(C + 5):ibm)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(ibm)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(llvm)}) -// CHECK-NEXT: template T barbar(); +// CHECK-NEXT: template T barbar(); #pragma omp declare variant(foofoo ) match(xxx = {}) #pragma omp declare variant(foofoo ) match(xxx = {vvv}) #pragma omp declare variant(foofoo ) match(user = {score() : condition()}) @@ -39,19 +42,21 @@ int bar(); #pragma omp declare variant(foofoo ) match(user = {condition()}) #pragma omp declare variant(foofoo ) match(implementation={vendor(ibm)}, implementation={vendor(llvm)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) -template +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm)}) +template T barbar(); -// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) +// CHECK: #pragma omp declare variant(foofoo) match(implementation={vendor(score(3 + 5):ibm)}) +// CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(unknown)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(ibm)}) // CHECK-NEXT: #pragma omp declare variant(foofoo) match(implementation={vendor(llvm)}) -// CHECK-NEXT: template<> int barbar(); +// CHECK-NEXT: template<> int barbar(); // CHECK-NEXT: int baz() { -// CHECK-NEXT: return barbar(); +// CHECK-NEXT: return barbar(); // CHECK-NEXT: } int baz() { - return barbar(); + return barbar(); } // CHECK: template void h_ref(C *hp, C *hp2, C *hq, C *lin) { diff --git a/test/OpenMP/declare_variant_messages.c b/test/OpenMP/declare_variant_messages.c index 0eeaae052302..7e69cec1f1b0 100644 --- a/test/OpenMP/declare_variant_messages.c +++ b/test/OpenMP/declare_variant_messages.c @@ -30,6 +30,11 @@ int foo(void); #pragma omp declare variant(foo) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} +#pragma omp declare variant(foo) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} +#pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} +#pragma omp declare variant(foo) match(implementation={vendor(score(foo()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integer constant expression}} +#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm)}) int bar(void); // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} diff --git a/test/OpenMP/declare_variant_messages.cpp b/test/OpenMP/declare_variant_messages.cpp index ca61c53b0f6c..88e724d12470 100644 --- a/test/OpenMP/declare_variant_messages.cpp +++ b/test/OpenMP/declare_variant_messages.cpp @@ -8,7 +8,7 @@ int foo(); template -T foofoo(); +T foofoo(); // expected-note 2 {{declared here}} #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} #pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} @@ -33,6 +33,11 @@ T foofoo(); #pragma omp declare variant(foofoo ) match(implementation={vendor}) // expected-error {{expected '(' after 'vendor'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-error {{expected ')'}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor()}) // expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(2 ibm)}) // expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm)}) int bar(); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} @@ -57,7 +62,12 @@ int bar(); #pragma omp declare variant(foofoo ) match(user = {condition()}) #pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} -template +#pragma omp declare variant(foofoo ) match(implementation={vendor(score ibm)}) // expected-error {{expected '(' after 'score'}} expected-warning {{missing ':' after context selector score clause - ignoring}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C ibm)}) // expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm)}) +template T barbar(); // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} From f44a44d2c094fea906a76aded17f8703570882f9 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Wed, 2 Oct 2019 18:33:44 +0000 Subject: [PATCH 02/33] [Stencil] Hide implementaion detai. NFC. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373504 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Tooling/Refactoring/Stencil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Tooling/Refactoring/Stencil.cpp b/lib/Tooling/Refactoring/Stencil.cpp index 78239b96d3c8..a01b81023389 100644 --- a/lib/Tooling/Refactoring/Stencil.cpp +++ b/lib/Tooling/Refactoring/Stencil.cpp @@ -82,7 +82,6 @@ struct IfBoundData { StencilPart TruePart; StencilPart FalsePart; }; -} // namespace bool isEqualData(const RawTextData &A, const RawTextData &B) { return A.Text == B.Text; @@ -203,6 +202,7 @@ class StencilPartImpl : public StencilPartInterface { return false; } }; +} // namespace StencilPart Stencil::wrap(StringRef Text) { return stencil::text(Text); From 418e4ac57a27cd1c62493255209d61db62a6d614 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Wed, 2 Oct 2019 20:30:37 +0000 Subject: [PATCH 03/33] CGObjCMac - silence static analyzer dyn_cast<>/getAs<> null dereference warnings. NFCI. The static analyzer is warning about potential null dereferences, but we should be able to use cast<>/castAs<> directly and if not assert will fire for us. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373520 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjCMac.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 12880fecbadf..2b92c4b9e6df 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2517,14 +2517,12 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, } if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { - const ConstantArrayType *CArray = - dyn_cast_or_null(Array); + auto *CArray = cast(Array); uint64_t ElCount = CArray->getSize().getZExtValue(); assert(CArray && "only array with known element size is supported"); FQT = CArray->getElementType(); while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { - const ConstantArrayType *CArray = - dyn_cast_or_null(Array); + auto *CArray = cast(Array); ElCount *= CArray->getSize().getZExtValue(); FQT = CArray->getElementType(); } @@ -4902,7 +4900,7 @@ LValue CGObjCMac::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { const ObjCInterfaceDecl *ID = - ObjectTy->getAs()->getInterface(); + ObjectTy->castAs()->getInterface(); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, EmitIvarOffset(CGF, ID, Ivar)); } @@ -7053,7 +7051,7 @@ LValue CGObjCNonFragileABIMac::EmitObjCValueForIvar( llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers) { - ObjCInterfaceDecl *ID = ObjectTy->getAs()->getInterface(); + ObjCInterfaceDecl *ID = ObjectTy->castAs()->getInterface(); llvm::Value *Offset = EmitIvarOffset(CGF, ID, Ivar); return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, Offset); From 5eb4fe34ff21cd5e25d18be04757222e65e60d44 Mon Sep 17 00:00:00 2001 From: Sergey Dmitriev Date: Wed, 2 Oct 2019 20:44:45 +0000 Subject: [PATCH 04/33] [Clang][Driver][NFC] Corrected DeviceActionBuilder methods' comments. Differential Revision: https://reviews.llvm.org/D68355 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373523 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/Driver.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 94d50d713c87..5233691be60a 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2281,12 +2281,10 @@ class OffloadingActionBuilder final { return ABRT_Inactive; } - /// Append top level actions generated by the builder. Return true if errors - /// were found. + /// Append top level actions generated by the builder. virtual void appendTopLevelActions(ActionList &AL) {} - /// Append linker actions generated by the builder. Return true if errors - /// were found. + /// Append linker actions generated by the builder. virtual void appendLinkDependences(OffloadAction::DeviceDependences &DA) {} /// Initialize the builder. Return true if any initialization errors are From 8147b006f14ef0d1d07a39a4baf319434412fc88 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Wed, 2 Oct 2019 20:45:16 +0000 Subject: [PATCH 05/33] ItaniumCXXABI - silence static analyzer getAs null dereference warnings. NFCI. The static analyzer is warning about potential null dereferences, but we should be able to use castAs directly and if not assert will fire for us. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373525 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/ItaniumCXXABI.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index e5eed43d3887..d6e51c60cc7f 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -580,8 +580,8 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( const FunctionProtoType *FPT = MPT->getPointeeType()->getAs(); - const CXXRecordDecl *RD = - cast(MPT->getClass()->getAs()->getDecl()); + auto *RD = + cast(MPT->getClass()->castAs()->getDecl()); llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType( CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr)); @@ -1143,7 +1143,7 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, // Grab the vtable pointer as an intptr_t*. auto *ClassDecl = - cast(ElementType->getAs()->getDecl()); + cast(ElementType->castAs()->getDecl()); llvm::Value *VTable = CGF.GetVTablePtr(Ptr, CGF.IntPtrTy->getPointerTo(), ClassDecl); @@ -1346,7 +1346,7 @@ llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF, Address ThisPtr, llvm::Type *StdTypeInfoPtrTy) { auto *ClassDecl = - cast(SrcRecordTy->getAs()->getDecl()); + cast(SrcRecordTy->castAs()->getDecl()); llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo(), ClassDecl); @@ -1412,7 +1412,7 @@ llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Type *DestLTy = CGF.ConvertType(DestTy); auto *ClassDecl = - cast(SrcRecordTy->getAs()->getDecl()); + cast(SrcRecordTy->castAs()->getDecl()); // Get the vtable pointer. llvm::Value *VTable = CGF.GetVTablePtr(ThisAddr, PtrDiffLTy->getPointerTo(), ClassDecl); @@ -3100,8 +3100,8 @@ static bool CanUseSingleInheritance(const CXXRecordDecl *RD) { return false; // Check that the class is dynamic iff the base is. - const CXXRecordDecl *BaseDecl = - cast(Base->getType()->getAs()->getDecl()); + auto *BaseDecl = + cast(Base->getType()->castAs()->getDecl()); if (!BaseDecl->isEmpty() && BaseDecl->isDynamicClass() != RD->isDynamicClass()) return false; @@ -3564,8 +3564,8 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, unsigned Flags = 0; - const CXXRecordDecl *BaseDecl = - cast(Base->getType()->getAs()->getDecl()); + auto *BaseDecl = + cast(Base->getType()->castAs()->getDecl()); if (Base->isVirtual()) { // Mark the virtual base as seen. @@ -3663,8 +3663,8 @@ void ItaniumRTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // The __base_type member points to the RTTI for the base type. Fields.push_back(ItaniumRTTIBuilder(CXXABI).BuildTypeInfo(Base.getType())); - const CXXRecordDecl *BaseDecl = - cast(Base.getType()->getAs()->getDecl()); + auto *BaseDecl = + cast(Base.getType()->castAs()->getDecl()); int64_t OffsetFlags = 0; From 6aa1f42be9f8fc0a416590815e92e42cdad60fa3 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Wed, 2 Oct 2019 21:05:21 +0000 Subject: [PATCH 06/33] Fix uninitialized variable warning in CodeGenPGO constructor. NFCI. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373526 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenPGO.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h index 2e740f789243..a3778b549910 100644 --- a/lib/CodeGen/CodeGenPGO.h +++ b/lib/CodeGen/CodeGenPGO.h @@ -41,8 +41,8 @@ class CodeGenPGO { public: CodeGenPGO(CodeGenModule &CGM) - : CGM(CGM), NumValueSites({{0}}), NumRegionCounters(0), FunctionHash(0), - CurrentRegionCount(0) {} + : CGM(CGM), FuncNameVar(nullptr), NumValueSites({{0}}), + NumRegionCounters(0), FunctionHash(0), CurrentRegionCount(0) {} /// Whether or not we have PGO region data for the current function. This is /// false both when we have no data at all and when our data has been From 2b8b74a6ff09a52dcd751e5429f4be32899ae3a3 Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Wed, 2 Oct 2019 22:50:07 +0000 Subject: [PATCH 07/33] [clang][ifs] Clang Interface Stubs ToolChain plumbing. This patch enables end to end support for generating ELF interface stubs directly from clang. Now the following: clang -emit-interface-stubs -o libfoo.so a.cpp b.cpp c.cpp will product an ELF binary with visible symbols populated. Visibility attributes and -fvisibility can be used to control what gets populated. * Adding ToolChain support for clang Driver IFS Merge Phase * Implementing a default InterfaceStubs Merge clang Tool, used by ToolChain * Adds support for the clang Driver to involve llvm-ifs on ifs files. * Adds -emit-merged-ifs flag, to tell llvm-ifs to emit a merged ifs text file instead of the final object format (normally ELF) Differential Revision: https://reviews.llvm.org/D63978 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373538 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Action.h | 12 ++++++ include/clang/Driver/Options.td | 3 ++ include/clang/Driver/Phases.h | 3 +- include/clang/Driver/ToolChain.h | 2 + include/clang/Driver/Types.def | 3 +- lib/Driver/Action.cpp | 6 +++ lib/Driver/CMakeLists.txt | 1 + lib/Driver/Driver.cpp | 36 +++++++++++++---- lib/Driver/Phases.cpp | 1 + lib/Driver/ToolChain.cpp | 10 +++++ lib/Driver/ToolChains/Clang.cpp | 25 ++---------- lib/Driver/ToolChains/InterfaceStubs.cpp | 37 +++++++++++++++++ lib/Driver/ToolChains/InterfaceStubs.h | 36 +++++++++++++++++ lib/Driver/Types.cpp | 18 ++++++++- lib/Frontend/CompilerInvocation.cpp | 23 ++++++----- test/InterfaceStubs/bad-format.cpp | 21 +++++----- .../class-template-specialization.cpp | 4 +- test/InterfaceStubs/conflict-type.ifs | 16 ++++++++ test/InterfaceStubs/driver-test.c | 12 ++++++ test/InterfaceStubs/externstatic.c | 26 +++++------- test/InterfaceStubs/func.ifs | 40 +++++++++++++++++++ .../function-template-specialization.cpp | 8 ++-- test/InterfaceStubs/inline.c | 33 +++++++-------- test/InterfaceStubs/merge-conflict-test.c | 3 ++ test/InterfaceStubs/object-double.c | 5 +++ test/InterfaceStubs/object-float.c | 3 ++ test/InterfaceStubs/object.c | 7 ++++ test/InterfaceStubs/object.ifs | 28 +++++++++++++ .../template-namespace-function.cpp | 2 +- test/InterfaceStubs/weak.cpp | 2 +- test/lit.cfg.py | 4 +- 31 files changed, 333 insertions(+), 97 deletions(-) create mode 100644 lib/Driver/ToolChains/InterfaceStubs.cpp create mode 100644 lib/Driver/ToolChains/InterfaceStubs.h create mode 100644 test/InterfaceStubs/conflict-type.ifs create mode 100644 test/InterfaceStubs/driver-test.c create mode 100644 test/InterfaceStubs/func.ifs create mode 100644 test/InterfaceStubs/merge-conflict-test.c create mode 100644 test/InterfaceStubs/object-double.c create mode 100644 test/InterfaceStubs/object-float.c create mode 100644 test/InterfaceStubs/object.c create mode 100644 test/InterfaceStubs/object.ifs diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index c1ff0b1a6023..c6e90b297835 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -65,6 +65,7 @@ class Action { BackendJobClass, AssembleJobClass, LinkJobClass, + IfsMergeJobClass, LipoJobClass, DsymutilJobClass, VerifyDebugInfoJobClass, @@ -485,6 +486,17 @@ class AssembleJobAction : public JobAction { } }; +class IfsMergeJobAction : public JobAction { + void anchor() override; + +public: + IfsMergeJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == IfsMergeJobClass; + } +}; + class LinkJobAction : public JobAction { void anchor() override; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index d31c4f46e6b4..7fe99e2013b6 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -633,6 +633,9 @@ def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group; def emit_iterface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group, HelpText<"Generate Inteface Stub Files.">; +def emit_merged_ifs : Flag<["-"], "emit-merged-ifs">, + Flags<[CC1Option]>, Group, + HelpText<"Generate Interface Stub Files, emit merged text not binary.">; def iterface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version=">, Flags<[CC1Option]>; def exported__symbols__list : Separate<["-"], "exported_symbols_list">; def e : JoinedOrSeparate<["-"], "e">, Group; diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h index 7199c657848c..63931c00c890 100644 --- a/include/clang/Driver/Phases.h +++ b/include/clang/Driver/Phases.h @@ -20,7 +20,8 @@ namespace phases { Compile, Backend, Assemble, - Link + Link, + IfsMerge, }; enum { diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index d6ed87574faa..2ba16ab21a92 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -136,11 +136,13 @@ class ToolChain { mutable std::unique_ptr Clang; mutable std::unique_ptr Assemble; mutable std::unique_ptr Link; + mutable std::unique_ptr IfsMerge; mutable std::unique_ptr OffloadBundler; Tool *getClang() const; Tool *getAssemble() const; Tool *getLink() const; + Tool *getIfsMerge() const; Tool *getClangAs() const; Tool *getOffloadBundler() const; diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index a33598e7b7f0..79e8d109cd97 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -84,7 +84,8 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases // Misc. TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link) -TYPE("ifs", IFS, INVALID, "ifs", phases::Compile, phases::Backend, phases::Assemble, phases::Link) +TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge) +TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge) TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", phases::Compile, phases::Backend, phases::Assemble, phases::Link) diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 47b03f6643b8..0187cf981eb5 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -31,6 +31,7 @@ const char *Action::getClassName(ActionClass AC) { case CompileJobClass: return "compiler"; case BackendJobClass: return "backend"; case AssembleJobClass: return "assembler"; + case IfsMergeJobClass: return "interface-stub-merger"; case LinkJobClass: return "linker"; case LipoJobClass: return "lipo"; case DsymutilJobClass: return "dsymutil"; @@ -357,6 +358,11 @@ void AssembleJobAction::anchor() {} AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) : JobAction(AssembleJobClass, Input, OutputType) {} +void IfsMergeJobAction::anchor() {} + +IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type) + : JobAction(IfsMergeJobClass, Inputs, Type) {} + void LinkJobAction::anchor() {} LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index d90c0ff43607..64b5d70f42b6 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -66,6 +66,7 @@ add_clang_library(clangDriver ToolChains/WebAssembly.cpp ToolChains/XCore.cpp ToolChains/PPCLinux.cpp + ToolChains/InterfaceStubs.cpp Types.cpp XRayArgs.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 5233691be60a..de7ca40d0cd3 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -274,11 +274,11 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; - // --precompile only runs up to precompilation. + // --precompile only runs up to precompilation. } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { FinalPhase = phases::Precompile; - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || @@ -286,20 +286,23 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || - (PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; - // -S only runs up to the backend. + // clang interface stubs + } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs))) { + FinalPhase = phases::IfsMerge; + + // -S only runs up to the backend. } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; - // -c compilation only runs up to the assembler. + // -c compilation only runs up to the assembler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; - // Otherwise do everything. + // Otherwise do everything. } else FinalPhase = phases::Link; @@ -3323,6 +3326,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Construct the actions to perform. HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; ActionList LinkerInputs; + ActionList MergerInputs; for (auto &I : Inputs) { types::ID InputType = I.first; @@ -3360,6 +3364,17 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, break; } + // TODO: Consider removing this because the merged may not end up being + // the final Phase in the pipeline. Perhaps the merged could just merge + // and then pass an artifact of some sort to the Link Phase. + // Queue merger inputs. + if (Phase == phases::IfsMerge) { + assert(Phase == PL.back() && "merging must be final compilation step."); + MergerInputs.push_back(Current); + Current = nullptr; + break; + } + // Each precompiled header file after a module file action is a module // header of that same module file, rather than being compiled to a // separate PCH. @@ -3409,6 +3424,11 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back(LA); } + // Add an interface stubs merge action if necessary. + if (!MergerInputs.empty()) + Actions.push_back( + C.MakeAction(MergerInputs, types::TY_Image)); + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { @@ -3445,6 +3465,8 @@ Action *Driver::ConstructPhaseAction( switch (Phase) { case phases::Link: llvm_unreachable("link action invalid here."); + case phases::IfsMerge: + llvm_unreachable("ifsmerge action invalid here."); case phases::Preprocess: { types::ID OutputTy; // -M and -MM specify the dependency file name by altering the output type, @@ -3509,7 +3531,7 @@ Action *Driver::ConstructPhaseAction( if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction(Input, types::TY_Nothing); if (Args.hasArg(options::OPT_emit_iterface_stubs)) - return C.MakeAction(Input, types::TY_IFS); + return C.MakeAction(Input, types::TY_IFS_CPP); return C.MakeAction(Input, types::TY_LLVM_BC); } case phases::Backend: { diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp index 5b776c63f713..01598c59bd9e 100644 --- a/lib/Driver/Phases.cpp +++ b/lib/Driver/Phases.cpp @@ -20,6 +20,7 @@ const char *phases::getPhaseName(ID Id) { case Backend: return "backend"; case Assemble: return "assembler"; case Link: return "linker"; + case IfsMerge: return "ifsmerger"; } llvm_unreachable("Invalid phase id."); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 4379da99d07b..db2497a10856 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -10,6 +10,7 @@ #include "InputInfo.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" +#include "ToolChains/InterfaceStubs.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -279,6 +280,12 @@ Tool *ToolChain::getLink() const { return Link.get(); } +Tool *ToolChain::getIfsMerge() const { + if (!IfsMerge) + IfsMerge.reset(new tools::ifstool::Merger(*this)); + return IfsMerge.get(); +} + Tool *ToolChain::getOffloadBundler() const { if (!OffloadBundler) OffloadBundler.reset(new tools::OffloadBundler(*this)); @@ -290,6 +297,9 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::AssembleJobClass: return getAssemble(); + case Action::IfsMergeJobClass: + return getIfsMerge(); + case Action::LinkJobClass: return getLink(); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 8628741f7dae..26e8bc60bfa4 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -3683,32 +3683,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) { CmdArgs.push_back("-emit-llvm-bc"); - } else if (JA.getType() == types::TY_IFS) { + } else if (JA.getType() == types::TY_IFS || + JA.getType() == types::TY_IFS_CPP) { StringRef ArgStr = Args.hasArg(options::OPT_iterface_stub_version_EQ) ? Args.getLastArgValue(options::OPT_iterface_stub_version_EQ) - : ""; - StringRef StubFormat = - llvm::StringSwitch(ArgStr) - .Case("experimental-ifs-v1", "experimental-ifs-v1") - .Default(""); - - if (StubFormat.empty()) { - std::string ErrorMessage = - "Invalid interface stub format: " + ArgStr.str() + - ((ArgStr == "experimental-yaml-elf-v1" || - ArgStr == "experimental-tapi-elf-v1") - ? " is deprecated." - : "."); - D.Diag(diag::err_drv_invalid_value) - << "Must specify a valid interface stub format type, ie: " - "-interface-stub-version=experimental-ifs-v1" - << ErrorMessage; - } - + : "experimental-ifs-v1"; CmdArgs.push_back("-emit-interface-stubs"); CmdArgs.push_back( - Args.MakeArgString(Twine("-interface-stub-version=") + StubFormat)); + Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str())); } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { diff --git a/lib/Driver/ToolChains/InterfaceStubs.cpp b/lib/Driver/ToolChains/InterfaceStubs.cpp new file mode 100644 index 000000000000..6677843b2c53 --- /dev/null +++ b/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -0,0 +1,37 @@ +//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "InterfaceStubs.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" + +namespace clang { +namespace driver { +namespace tools { +namespace ifstool { +void Merger::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + const char *LinkingOutput) const { + std::string Merger = getToolChain().GetProgramPath(getShortName()); + llvm::opt::ArgStringList CmdArgs; + CmdArgs.push_back("-action"); + CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) + ? "write-ifs" + : "write-bin"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + for (const auto &Input : Inputs) + CmdArgs.push_back(Input.getFilename()); + C.addCommand(std::make_unique(JA, *this, Args.MakeArgString(Merger), + CmdArgs, Inputs)); +} +} // namespace ifstool +} // namespace tools +} // namespace driver +} // namespace clang diff --git a/lib/Driver/ToolChains/InterfaceStubs.h b/lib/Driver/ToolChains/InterfaceStubs.h new file mode 100644 index 000000000000..4afa73701a4c --- /dev/null +++ b/lib/Driver/ToolChains/InterfaceStubs.h @@ -0,0 +1,36 @@ +//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace ifstool { +class LLVM_LIBRARY_VISIBILITY Merger : public Tool { +public: + Merger(const ToolChain &TC) : Tool("IFS::Merger", "llvm-ifs", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace ifstool +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index da01e1acfcaa..6241fac0c85a 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -269,6 +269,7 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("lib", TY_Object) .Case("mii", TY_PP_ObjCXX) .Case("obj", TY_Object) + .Case("ifs", TY_IFS) .Case("pch", TY_PCH) .Case("pcm", TY_ModuleFile) .Case("c++m", TY_CXXModule) @@ -319,6 +320,22 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::copy_if(PhaseList, std::back_inserter(P), [](phases::ID Phase) { return Phase <= phases::Precompile; }); + // Treat Interface Stubs like its own compilation mode. + else if (DAL.getLastArg(options::OPT_emit_iterface_stubs)) { + llvm::SmallVector IfsModePhaseList; + llvm::SmallVector &PL = PhaseList; + phases::ID LastPhase = phases::IfsMerge; + if (Id != types::TY_IFS) { + if (DAL.hasArg(options::OPT_c)) + LastPhase = phases::Compile; + PL = IfsModePhaseList; + types::getCompilationPhases(types::TY_IFS_CPP, PL); + } + llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { + return Phase <= LastPhase; + }); + } + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. else if (DAL.getLastArg(options::OPT_fsyntax_only) || DAL.getLastArg(options::OPT_print_supported_cpus) || @@ -327,7 +344,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, DAL.getLastArg(options::OPT_rewrite_objc) || DAL.getLastArg(options::OPT_rewrite_legacy_objc) || DAL.getLastArg(options::OPT__migrate) || - DAL.getLastArg(options::OPT_emit_iterface_stubs) || DAL.getLastArg(options::OPT__analyze) || DAL.getLastArg(options::OPT_emit_ast)) llvm::copy_if(PhaseList, std::back_inserter(P), diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 61a2c07890fc..6fc8afcf3c66 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1734,24 +1734,25 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, StringRef ArgStr = Args.hasArg(OPT_iterface_stub_version_EQ) ? Args.getLastArgValue(OPT_iterface_stub_version_EQ) - : ""; - llvm::Optional ProgramAction = - llvm::StringSwitch>(ArgStr) - .Case("experimental-ifs-v1", frontend::GenerateInterfaceIfsExpV1) - .Default(llvm::None); - if (!ProgramAction) { + : "experimental-ifs-v1"; + if (ArgStr == "experimental-yaml-elf-v1" || + ArgStr == "experimental-tapi-elf-v1") { std::string ErrorMessage = "Invalid interface stub format: " + ArgStr.str() + - ((ArgStr == "experimental-yaml-elf-v1" || - ArgStr == "experimental-tapi-elf-v1") - ? " is deprecated." - : "."); + " is deprecated."; + Diags.Report(diag::err_drv_invalid_value) + << "Must specify a valid interface stub format type, ie: " + "-interface-stub-version=experimental-ifs-v1" + << ErrorMessage; + } else if (ArgStr != "experimental-ifs-v1") { + std::string ErrorMessage = + "Invalid interface stub format: " + ArgStr.str() + "."; Diags.Report(diag::err_drv_invalid_value) << "Must specify a valid interface stub format type, ie: " "-interface-stub-version=experimental-ifs-v1" << ErrorMessage; } else { - Opts.ProgramAction = *ProgramAction; + Opts.ProgramAction = frontend::GenerateInterfaceIfsExpV1; } break; } diff --git a/test/InterfaceStubs/bad-format.cpp b/test/InterfaceStubs/bad-format.cpp index f13ea2fc76b3..4d51ac867eb2 100644 --- a/test/InterfaceStubs/bad-format.cpp +++ b/test/InterfaceStubs/bad-format.cpp @@ -1,28 +1,25 @@ -// REQUIRES: x86-registered-target -// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=bar-format %s 2>&1 | FileCheck %s +// RUN: not %clang -emit-interface-stubs -interface-stub-version=bad-format %s 2>&1 | \ +// RUN: FileCheck %s -// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ +// RUN: not %clang -emit-interface-stubs -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-TAPI-DEPRECATED %s -// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ +// RUN: not %clang -emit-interface-stubs -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-YAML-DEPRECATED %s -// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=bar-format %s 2>&1 | FileCheck %s +// RUN: not %clang -emit-interface-stubs -interface-stub-version=bad-format %s 2>&1 | \ +// RUN: FileCheck %s -// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: not %clang -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-TAPI-DEPRECATED %s -// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: not %clang -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-YAML-DEPRECATED %s // CHECK: error: invalid value -// CHECK: 'Invalid interface stub format: bar-format.' in 'Must specify a +// CHECK: 'Invalid interface stub format: bad-format.' in 'Must specify a // CHECK: valid interface stub format type, ie: // CHECK: -interface-stub-version=experimental-ifs-v1' diff --git a/test/InterfaceStubs/class-template-specialization.cpp b/test/InterfaceStubs/class-template-specialization.cpp index 29e459390495..0a68d3f1f117 100644 --- a/test/InterfaceStubs/class-template-specialization.cpp +++ b/test/InterfaceStubs/class-template-specialization.cpp @@ -1,9 +1,9 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck -check-prefix=CHECK-TAPI %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck -check-prefix=CHECK-TAPI2 %s // RUN: %clang -target x86_64-unknown-linux-gnu -o - -c %s | \ diff --git a/test/InterfaceStubs/conflict-type.ifs b/test/InterfaceStubs/conflict-type.ifs new file mode 100644 index 000000000000..aaa04775e317 --- /dev/null +++ b/test/InterfaceStubs/conflict-type.ifs @@ -0,0 +1,16 @@ +# RUN: not %clang -emit-merged-ifs -emit-interface-stubs -o - %s %S/func.ifs 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=CHECK-IFS + +# Here we are testing to see if two symbols with identical names will fail to +# merge in conflict due to mismatched types. +# CHECK-IFS: error: Interface Stub: Type Mismatch for a. +# CHECK-IFS-NEXT: Filename: +# CHECK-IFS-NEXT: Type Values: Object Func + +--- !experimental-ifs-v1 +IfsVersion: 1.0 +Triple: x86_64-linux-gnu +ObjectFileFormat: ELF +Symbols: + a: { Type: Object, Size: 1 } +... diff --git a/test/InterfaceStubs/driver-test.c b/test/InterfaceStubs/driver-test.c new file mode 100644 index 000000000000..e2755b9b9351 --- /dev/null +++ b/test/InterfaceStubs/driver-test.c @@ -0,0 +1,12 @@ +// RUN: %clang -x c -o libfoo.so -emit-interface-stubs %s %S/object.c %S/weak.cpp && \ +// RUN: llvm-nm libfoo.so 2>&1 | FileCheck %s + +// RUN: %clang -x c -o libfoo.so -shared %s %S/object.c %S/weak.cpp && \ +// RUN: llvm-nm libfoo.so 2>&1 | FileCheck %s + +// CHECK-DAG: data +// CHECK-DAG: foo +// CHECK-DAG: strongFunc +// CHECK-DAG: weakFunc + +int foo(int bar) { return 42 + 1844; } \ No newline at end of file diff --git a/test/InterfaceStubs/externstatic.c b/test/InterfaceStubs/externstatic.c index bc1aef477bcd..37d5b7db19a2 100644 --- a/test/InterfaceStubs/externstatic.c +++ b/test/InterfaceStubs/externstatic.c @@ -1,24 +1,20 @@ -// REQUIRES: x86-registered-target -// RUN: %clang -DSTORAGE="extern" -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DSTORAGE="extern" -o - -emit-interface-stubs -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-EXTERN %s -// RUN: %clang -DSTORAGE="extern" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ + +// RUN: %clang -DSTORAGE="extern" -O0 -o - -c -std=c99 \ // RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-EXTERN %s -// RUN: %clang -DSTORAGE="extern" -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DSTORAGE="extern" -o - -emit-interface-stubs -std=c99 -xc %s | \ +// RUN: FileCheck -check-prefix=CHECK-EXTERN2 %s + +// RUN: %clang -DSTORAGE="extern" -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-EXTERN2 %s -// RUN: %clang -DSTORAGE="extern" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ -// RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-EXTERN2 %s -// RUN: %clang -DSTORAGE="static" -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DSTORAGE="static" -o - -emit-interface-stubs -std=c99 -xc %s | \ +// RUN: FileCheck -check-prefix=CHECK-STATIC %s + +// RUN: %clang -DSTORAGE="static" -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-STATIC %s -// RUN: %clang -DSTORAGE="static" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ -// RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-STATIC %s // CHECK-EXTERN-NOT: foo // CHECK-STATIC-NOT: foo diff --git a/test/InterfaceStubs/func.ifs b/test/InterfaceStubs/func.ifs new file mode 100644 index 000000000000..d115523bfda4 --- /dev/null +++ b/test/InterfaceStubs/func.ifs @@ -0,0 +1,40 @@ +# RUN: %clang -emit-interface-stubs -o - %s %S/object.ifs -emit-merged-ifs | \ +# RUN: FileCheck %s --check-prefixes=CHECK-IFS + +# RUN: %clang -emit-interface-stubs -o - %s %S/object.ifs | llvm-readelf --all | \ +# RUN: FileCheck %s --check-prefixes=CHECK-ELF + +# RUN: %clang -emit-interface-stubs -o - %s %s -emit-merged-ifs | \ +# RUN: FileCheck %s --check-prefixes=CHECK-MERGE-IFS + +# CHECK-IFS: --- !experimental-ifs-v1 +# CHECK-IFS-NEXT: IfsVersion: 1.0 +# CHECK-IFS-NEXT: Triple: x86_64-linux-gnu +# CHECK-IFS-NEXT: ObjectFileFormat: ELF +# CHECK-IFS-NEXT: Symbols: +# CHECK-IFS-DAG: a: { Type: Func } +# CHECK-IFS-DAG: b: { Type: Object, Size: 4 } +# CHECK-IFS: ... + +# CHECK-ELF: ELF Header: +# CHECK-ELF: Class: ELF64 +# CHECK-ELF: Type: DYN (Shared object file) +# CHECK-ELF: FUNC GLOBAL DEFAULT 1 a +# CHECK-ELF: OBJECT GLOBAL DEFAULT 1 b + +# Here we are testing to see if two identical symbols will merge. +# CHECK-MERGE-IFS: --- !experimental-ifs-v1 +# CHECK-MERGE-IFS-NEXT: IfsVersion: 1.0 +# CHECK-MERGE-IFS-NEXT: Triple: x86_64-linux-gnu +# CHECK-MERGE-IFS-NEXT: ObjectFileFormat: ELF +# CHECK-MERGE-IFS-NEXT: Symbols: +# CHECK-MERGE-IFS-NEXT: a: { Type: Func } +# CHECK-MERGE-IFS-NEXT: ... + +--- !experimental-ifs-v1 +IfsVersion: 1.0 +Triple: x86_64-linux-gnu +ObjectFileFormat: ELF +Symbols: + a: { Type: Func } +... diff --git a/test/InterfaceStubs/function-template-specialization.cpp b/test/InterfaceStubs/function-template-specialization.cpp index f6e5c87e7f44..f6ec64bcd916 100644 --- a/test/InterfaceStubs/function-template-specialization.cpp +++ b/test/InterfaceStubs/function-template-specialization.cpp @@ -1,13 +1,15 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ + +// TODO: Fix the case in llvm-ifs where it crashes on an empty Symbols list. +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -c \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | FileCheck %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 \ // RUN: -DUSE_TEMPLATE_FUNCTION=1 %s | \ // RUN: FileCheck -check-prefix=CHECK-USES-TEMPLATE-FUNCTION %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 \ // RUN: -DSPECIALIZE_TEMPLATE_FUNCTION=1 %s | \ // RUN: FileCheck -check-prefix=CHECK-SPECIALIZES-TEMPLATE-FUNCTION %s diff --git a/test/InterfaceStubs/inline.c b/test/InterfaceStubs/inline.c index e32b4e100960..06a58c4c1bea 100644 --- a/test/InterfaceStubs/inline.c +++ b/test/InterfaceStubs/inline.c @@ -1,37 +1,32 @@ // REQUIRES: x86-registered-target -// RUN: %clang -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=gnu89 -xc %s | \ +// RUN: %clang -c -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs -std=gnu89 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-GNU %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -O0 -o - -c \ // RUN: -std=gnu89 -xc %s | llvm-nm - | FileCheck -check-prefix=CHECK-GNU %s -// RUN: %clang -DINLINE="__attribute__((always_inline))" \ -// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -xc %s | \ +// RUN: %clang -c -DINLINE="__attribute__((always_inline))" \ +// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-GNU %s // RUN: %clang -DINLINE="__attribute__((always_inline))" \ // RUN: -target x86_64-linux-gnu -O0 -o - -c -xc %s | \ // RUN: llvm-nm - | FileCheck -check-prefix=CHECK-GNU %s -// RUN: %clang -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-STD %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ // RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-STD %s -// RUN: %clang -DINLINE="__attribute__((noinline))" \ -// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DINLINE="__attribute__((noinline))" \ +// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-NOINLINE %s // RUN: %clang -DINLINE="__attribute__((noinline))" -target x86_64-linux-gnu \ // RUN: -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-NOINLINE %s -// RUN: %clang -DINLINE="static" -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ +// RUN: %clang -c -DINLINE="static" -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-STATIC %s // RUN: %clang -DINLINE="static" -target x86_64-linux-gnu -O0 -o - -c \ // RUN: -std=c99 -xc %s | llvm-nm - 2>&1 | \ @@ -50,12 +45,12 @@ INLINE int foo() { return var; } -// RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ -// RUN: -emit-interface-stubs -interface-stub-version=experimental-ifs-v1 \ +// RUN: %clang -c -DINLINE=inline -target x86_64-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ // RUN: -std=gnu89 -xc %s | FileCheck -check-prefix=CHECK-TAPI %s -// RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ -// RUN: -emit-interface-stubs -interface-stub-version=experimental-ifs-v1 \ +// RUN: %clang -c -DINLINE=inline -target x86_64-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ // RUN: -std=gnu89 -xc %s | FileCheck -check-prefix=CHECK-SYMBOLS %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ // RUN: -c -std=gnu89 -xc %s | llvm-nm - 2>&1 | \ diff --git a/test/InterfaceStubs/merge-conflict-test.c b/test/InterfaceStubs/merge-conflict-test.c new file mode 100644 index 000000000000..2d006148ba46 --- /dev/null +++ b/test/InterfaceStubs/merge-conflict-test.c @@ -0,0 +1,3 @@ +// RUN: not %clang -o libfoo.so -emit-interface-stubs %s %S/driver-test.c 2>&1 | FileCheck %s +// CHECK: error: Interface Stub: Type Mismatch +int foo; \ No newline at end of file diff --git a/test/InterfaceStubs/object-double.c b/test/InterfaceStubs/object-double.c new file mode 100644 index 000000000000..c6d2b61a4d9e --- /dev/null +++ b/test/InterfaceStubs/object-double.c @@ -0,0 +1,5 @@ +// RUN: not %clang -o - -emit-interface-stubs %s %S/object.c 2>&1 | FileCheck %s +// Need to encode more type info or weak vs strong symbol resolution in llvm-ifs +// XFAIL: * +// CHECK: error: Interface Stub: Size Mismatch +float data = 42.0; \ No newline at end of file diff --git a/test/InterfaceStubs/object-float.c b/test/InterfaceStubs/object-float.c new file mode 100644 index 000000000000..6dd056bb852e --- /dev/null +++ b/test/InterfaceStubs/object-float.c @@ -0,0 +1,3 @@ +// RUN: not %clang -o - -emit-interface-stubs %s %S/object.c 2>&1 | FileCheck %s +// CHECK: error: Interface Stub: Size Mismatch +double data = 42.0; \ No newline at end of file diff --git a/test/InterfaceStubs/object.c b/test/InterfaceStubs/object.c new file mode 100644 index 000000000000..b07bea930e56 --- /dev/null +++ b/test/InterfaceStubs/object.c @@ -0,0 +1,7 @@ +// RUN: %clang -c -o - -emit-interface-stubs %s | FileCheck -check-prefix=CHECK-TAPI %s +// RUN: %clang -c -o - -emit-interface-stubs %s | FileCheck -check-prefix=CHECK-SYMBOLS %s +// RUN: %clang -c -o - %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-SYMBOLS %s + +// CHECK-TAPI: data: { Type: Object, Size: 4 } +// CHECK-SYMBOLS: data +int data = 42; diff --git a/test/InterfaceStubs/object.ifs b/test/InterfaceStubs/object.ifs new file mode 100644 index 000000000000..7dc1134bac93 --- /dev/null +++ b/test/InterfaceStubs/object.ifs @@ -0,0 +1,28 @@ +# RUN: %clang -emit-interface-stubs -o - -emit-merged-ifs %s | \ +# RUN: FileCheck %s --check-prefixes=CHECK-IFS + +# RUN: %clang -emit-interface-stubs -o - %s | llvm-readelf --all | \ +# RUN: FileCheck %s --check-prefixes=CHECK-ELF + +# CHECK-IFS: --- !experimental-ifs-v1 +# CHECK-IFS-NEXT: IfsVersion: 1.0 +# CHECK-IFS-NEXT: Triple: x86_64-linux-gnu +# CHECK-IFS-NEXT: ObjectFileFormat: ELF +# CHECK-IFS-NEXT: Symbols: +# CHECK-IFS-NEXT: b: { Type: Object, Size: 4 } +# CHECK-IFS-NEXT: ... + +# CHECK-ELF: ELF Header: +# CHECK-ELF: Class: ELF64 +# CHECK-ELF: Data: 2's complement, little endian +# CHECK-ELF: Type: DYN (Shared object file) +# CHECK-ELF-NOT: FUNC GLOBAL DEFAULT 1 a +# CHECK-ELF: OBJECT GLOBAL DEFAULT 1 b + +--- !experimental-ifs-v1 +IfsVersion: 1.0 +Triple: x86_64-linux-gnu +ObjectFileFormat: ELF +Symbols: + b: { Type: Object, Size: 4 } +... diff --git a/test/InterfaceStubs/template-namespace-function.cpp b/test/InterfaceStubs/template-namespace-function.cpp index 4956525b4060..ad8606757c9e 100644 --- a/test/InterfaceStubs/template-namespace-function.cpp +++ b/test/InterfaceStubs/template-namespace-function.cpp @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck %s diff --git a/test/InterfaceStubs/weak.cpp b/test/InterfaceStubs/weak.cpp index 13b7e5aa2938..e1c2c232a9d8 100644 --- a/test/InterfaceStubs/weak.cpp +++ b/test/InterfaceStubs/weak.cpp @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: %clang -target x86_64-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck %s diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 9ffe30ec50d5..1ffb6d094d72 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -26,7 +26,7 @@ # suffixes: A list of file extensions to treat as test files. config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu', - '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs'] + '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs', '.ifs'] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent @@ -61,7 +61,7 @@ tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] tools = [ - 'c-index-test', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', + 'c-index-test', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', 'llvm-ifs', ToolSubst('%clang_extdef_map', command=FindTool( 'clang-extdef-mapping'), unresolved='ignore'), ] From 9e958d35f4fe1b7dab920fc9da1c85757df0176d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 00:39:33 +0000 Subject: [PATCH 08/33] For P0784R7: allow direct calls to operator new / operator delete from std::allocator::{allocate,deallocate} in constant evaluation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373546 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticASTKinds.td | 15 +- lib/AST/ExprConstant.cpp | 355 +++++++++++++++++----- test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | 85 ++++++ 3 files changed, 374 insertions(+), 81 deletions(-) create mode 100644 test/SemaCXX/cxx2a-constexpr-dynalloc.cpp diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index f4eeebd73ab6..69d30b4eb3f8 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -272,6 +272,13 @@ def note_constexpr_new_too_large : Note< def note_constexpr_new_too_small : Note< "cannot allocate array; evaluated array bound %0 is too small to hold " "%1 explicitly initialized elements">; +def note_constexpr_new_untyped : Note< + "cannot allocate untyped memory in a constant expression; " + "use 'std::allocator::allocate' to allocate memory of type 'T'">; +def note_constexpr_new_not_complete_object_type : Note< + "cannot allocate memory of %select{incomplete|function}0 type %1">; +def note_constexpr_operator_new_bad_size : Note< + "allocated size %0 is not a multiple of size %1 of element type %2">; def note_constexpr_delete_not_heap_alloc : Note< "delete of pointer '%0' that does not point to a heap-allocated object">; def note_constexpr_double_delete : Note< @@ -279,8 +286,12 @@ def note_constexpr_double_delete : Note< def note_constexpr_double_destroy : Note< "destruction of object that is already being destroyed">; def note_constexpr_new_delete_mismatch : Note< - "%select{non-|}0array delete used to delete pointer to " - "%select{|non-}0array object of type %1">; + "%plural{2:'delete' used to delete pointer to object " + "allocated with 'std::allocator<...>::allocate'|" + ":%select{non-array delete|array delete|'std::allocator<...>::deallocate'}0 " + "used to delete pointer to " + "%select{array object of type %2|non-array object of type %2|" + "object allocated with 'new'}0}1">; def note_constexpr_delete_subobject : Note< "delete of pointer%select{ to subobject|}1 '%0' " "%select{|that does not point to complete object}1">; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 55776d03f0ca..669acd3a6669 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -690,6 +690,37 @@ template<> struct DenseMapInfo { } namespace { + /// A dynamically-allocated heap object. + struct DynAlloc { + /// The value of this heap-allocated object. + APValue Value; + /// The allocating expression; used for diagnostics. Either a CXXNewExpr + /// or a CallExpr (the latter is for direct calls to operator new inside + /// std::allocator::allocate). + const Expr *AllocExpr = nullptr; + + enum Kind { + New, + ArrayNew, + StdAllocator + }; + + /// Get the kind of the allocation. This must match between allocation + /// and deallocation. + Kind getKind() const { + if (auto *NE = dyn_cast(AllocExpr)) + return NE->isArray() ? ArrayNew : New; + assert(isa(AllocExpr)); + return StdAllocator; + } + }; + + struct DynAllocOrder { + bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const { + return L.getIndex() < R.getIndex(); + } + }; + /// EvalInfo - This is a private struct used by the evaluator to capture /// information about a subexpression as it is folded. It retains information /// about the AST context, but also maintains information about the folded @@ -761,20 +792,6 @@ namespace { llvm::DenseMap ObjectsUnderConstruction; - /// A dynamically-allocated heap object. - struct DynAlloc { - /// The value of this heap-allocated object. - APValue Value; - /// The allocating expression; used for diagnostics. - const Expr *AllocExpr = nullptr; - }; - - struct DynAllocOrder { - bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const { - return L.getIndex() < R.getIndex(); - } - }; - /// Current heap allocations, along with the location where each was /// allocated. We use std::map here because we need stable addresses /// for the stored APValues. @@ -970,6 +987,39 @@ namespace { return Result; } + /// Information about a stack frame for std::allocator::[de]allocate. + struct StdAllocatorCaller { + unsigned FrameIndex; + QualType ElemType; + explicit operator bool() const { return FrameIndex != 0; }; + }; + + StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const { + for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame; + Call = Call->Caller) { + const auto *MD = dyn_cast_or_null(Call->Callee); + if (!MD) + continue; + const IdentifierInfo *FnII = MD->getIdentifier(); + if (!FnII || !FnII->isStr(FnName)) + continue; + + const auto *CTSD = + dyn_cast(MD->getParent()); + if (!CTSD) + continue; + + const IdentifierInfo *ClassII = CTSD->getIdentifier(); + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + if (CTSD->isInStdNamespace() && ClassII && + ClassII->isStr("allocator") && TAL.size() >= 1 && + TAL[0].getKind() == TemplateArgument::Type) + return {Call->Index, TAL[0].getAsType()}; + } + + return {}; + } + void performLifetimeExtension() { // Disable the cleanups for lifetime-extended temporaries. CleanupStack.erase( @@ -1453,9 +1503,10 @@ namespace { IsNullPtr = false; } - void setNull(QualType PointerTy, uint64_t TargetVal) { + void setNull(ASTContext &Ctx, QualType PointerTy) { Base = (Expr *)nullptr; - Offset = CharUnits::fromQuantity(TargetVal); + Offset = + CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy)); InvalidBase = false; Designator = SubobjectDesignator(PointerTy->getPointeeType()); IsNullPtr = true; @@ -1465,6 +1516,12 @@ namespace { set(B, true); } + std::string toString(ASTContext &Ctx, QualType T) const { + APValue Printable; + moveInto(Printable); + return Printable.getAsString(Ctx, T); + } + private: // Check that this LValue is not based on a null pointer. If it is, produce // a diagnostic and mark the designator as invalid. @@ -1905,7 +1962,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here); else if (DynamicAllocLValue DA = Base.dyn_cast()) { // FIXME: Produce a note for dangling pointers too. - if (Optional Alloc = Info.lookupDynamicAlloc(DA)) + if (Optional Alloc = Info.lookupDynamicAlloc(DA)) Info.Note((*Alloc)->AllocExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here); } @@ -3560,7 +3617,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal)) return CompleteObject(); } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast()) { - Optional Alloc = Info.lookupDynamicAlloc(DA); + Optional Alloc = Info.lookupDynamicAlloc(DA); if (!Alloc) { Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK; return CompleteObject(); @@ -5147,8 +5204,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, if (!E->isGLValue()) { // The value of a failed cast to pointer type is the null pointer value // of the required result type. - auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType()); - Ptr.setNull(E->getType(), TargetVal); + Ptr.setNull(Info.Ctx, E->getType()); return true; } @@ -5878,6 +5934,161 @@ static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc, return HandleDestructionImpl(Info, Loc, LV, Value, T); } +/// Perform a call to 'perator new' or to `__builtin_operator_new'. +static bool HandleOperatorNewCall(EvalInfo &Info, const CallExpr *E, + LValue &Result) { + if (Info.checkingPotentialConstantExpression() || + Info.SpeculativeEvaluationDepth) + return false; + + // This is permitted only within a call to std::allocator::allocate. + auto Caller = Info.getStdAllocatorCaller("allocate"); + if (!Caller) { + Info.FFDiag(E->getExprLoc(), Info.getLangOpts().CPlusPlus2a + ? diag::note_constexpr_new_untyped + : diag::note_constexpr_new); + return false; + } + + QualType ElemType = Caller.ElemType; + if (ElemType->isIncompleteType() || ElemType->isFunctionType()) { + Info.FFDiag(E->getExprLoc(), + diag::note_constexpr_new_not_complete_object_type) + << (ElemType->isIncompleteType() ? 0 : 1) << ElemType; + return false; + } + + APSInt ByteSize; + if (!EvaluateInteger(E->getArg(0), ByteSize, Info)) + return false; + bool IsNothrow = false; + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) { + EvaluateIgnoredValue(Info, E->getArg(I)); + IsNothrow |= E->getType()->isNothrowT(); + } + + CharUnits ElemSize; + if (!HandleSizeof(Info, E->getExprLoc(), ElemType, ElemSize)) + return false; + APInt Size, Remainder; + APInt ElemSizeAP(ByteSize.getBitWidth(), ElemSize.getQuantity()); + APInt::udivrem(ByteSize, ElemSizeAP, Size, Remainder); + if (Remainder != 0) { + // This likely indicates a bug in the implementation of 'std::allocator'. + Info.FFDiag(E->getExprLoc(), diag::note_constexpr_operator_new_bad_size) + << ByteSize << APSInt(ElemSizeAP, true) << ElemType; + return false; + } + + if (ByteSize.getActiveBits() > ConstantArrayType::getMaxSizeBits(Info.Ctx)) { + if (IsNothrow) { + Result.setNull(Info.Ctx, E->getType()); + return true; + } + + Info.FFDiag(E, diag::note_constexpr_new_too_large) << APSInt(Size, true); + return false; + } + + QualType AllocType = + Info.Ctx.getConstantArrayType(ElemType, Size, ArrayType::Normal, 0); + APValue *Val = Info.createHeapAlloc(E, AllocType, Result); + *Val = APValue(APValue::UninitArray(), 0, Size.getZExtValue()); + Result.addArray(Info, E, cast(AllocType)); + return true; +} + +static bool hasVirtualDestructor(QualType T) { + if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + if (CXXDestructorDecl *DD = RD->getDestructor()) + return DD->isVirtual(); + return false; +} + +/// Check that the given object is a suitable pointer to a heap allocation that +/// still exists and is of the right kind for the purpose of a deletion. +/// +/// On success, returns the heap allocation to deallocate. On failure, produces +/// a diagnostic and returns None. +static Optional CheckDeleteKind(EvalInfo &Info, const Expr *E, + const LValue &Pointer, + DynAlloc::Kind DeallocKind) { + auto PointerAsString = [&] { + return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy); + }; + + DynamicAllocLValue DA = Pointer.Base.dyn_cast(); + if (!DA) { + Info.FFDiag(E, diag::note_constexpr_delete_not_heap_alloc) + << PointerAsString(); + if (Pointer.Base) + NoteLValueLocation(Info, Pointer.Base); + return None; + } + + Optional Alloc = Info.lookupDynamicAlloc(DA); + if (!Alloc) { + Info.FFDiag(E, diag::note_constexpr_double_delete); + return None; + } + + QualType AllocType = Pointer.Base.getDynamicAllocType(); + if (DeallocKind != (*Alloc)->getKind()) { + Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch) + << DeallocKind << (*Alloc)->getKind() << AllocType; + NoteLValueLocation(Info, Pointer.Base); + return None; + } + + bool Subobject = false; + if (DeallocKind == DynAlloc::New) { + Subobject = Pointer.Designator.MostDerivedPathLength != 0 || + Pointer.Designator.isOnePastTheEnd(); + } else { + Subobject = Pointer.Designator.Entries.size() != 1 || + Pointer.Designator.Entries[0].getAsArrayIndex() != 0; + } + if (Subobject) { + Info.FFDiag(E, diag::note_constexpr_delete_subobject) + << PointerAsString() << Pointer.Designator.isOnePastTheEnd(); + return None; + } + + return Alloc; +} + +// Perform a call to 'operator delete' or '__builtin_operator_delete'. +bool HandleOperatorDeleteCall(EvalInfo &Info, const CallExpr *E) { + if (Info.checkingPotentialConstantExpression() || + Info.SpeculativeEvaluationDepth) + return false; + + // This is permitted only within a call to std::allocator::deallocate. + if (!Info.getStdAllocatorCaller("deallocate")) { + Info.FFDiag(E->getExprLoc()); + return true; + } + + LValue Pointer; + if (!EvaluatePointer(E->getArg(0), Pointer, Info)) + return false; + for (unsigned I = 1, N = E->getNumArgs(); I != N; ++I) + EvaluateIgnoredValue(Info, E->getArg(I)); + + if (Pointer.Designator.Invalid) + return false; + + // Deleting a null pointer has no effect. + if (Pointer.isNullPointer()) + return true; + + if (!CheckDeleteKind(Info, E, Pointer, DynAlloc::StdAllocator)) + return false; + + Info.HeapAllocs.erase(Pointer.Base.get()); + return true; +} + //===----------------------------------------------------------------------===// // Generic Evaluation //===----------------------------------------------------------------------===// @@ -6700,6 +6911,17 @@ class ExprEvaluatorBase FD = cast(CorrespondingCallOpSpecialization); } else FD = LambdaCallOp; + } else if (FD->isReplaceableGlobalAllocationFunction()) { + if (FD->getDeclName().getCXXOverloadedOperator() == OO_New || + FD->getDeclName().getCXXOverloadedOperator() == OO_Array_New) { + LValue Ptr; + if (!HandleOperatorNewCall(Info, E, Ptr)) + return false; + Ptr.moveInto(Result); + return true; + } else { + return HandleOperatorDeleteCall(Info, E); + } } } else return Error(E); @@ -7565,8 +7787,7 @@ class PointerExprEvaluator return true; } bool ZeroInitialization(const Expr *E) { - auto TargetVal = Info.Ctx.getTargetNullPointerValue(E->getType()); - Result.setNull(E->getType(), TargetVal); + Result.setNull(Info.Ctx, E->getType()); return true; } @@ -7693,12 +7914,22 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { // permitted in constant expressions in C++11. Bitcasts from cv void* are // also static_casts, but we disallow them as a resolution to DR1312. if (!E->getType()->isVoidPointerType()) { - Result.Designator.setInvalid(); - if (SubExpr->getType()->isVoidPointerType()) - CCEDiag(E, diag::note_constexpr_invalid_cast) - << 3 << SubExpr->getType(); - else - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + if (!Result.InvalidBase && !Result.Designator.Invalid && + !Result.IsNullPtr && + Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx), + E->getType()->getPointeeType()) && + Info.getStdAllocatorCaller("allocate")) { + // Inside a call to std::allocator::allocate and friends, we permit + // casting from void* back to cv1 T* for a pointer that points to a + // cv2 T. + } else { + Result.Designator.setInvalid(); + if (SubExpr->getType()->isVoidPointerType()) + CCEDiag(E, diag::note_constexpr_invalid_cast) + << 3 << SubExpr->getType(); + else + CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + } } if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr) ZeroInitialization(E); @@ -7935,6 +8166,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return true; } + case Builtin::BI__builtin_operator_new: + return HandleOperatorNewCall(Info, E, Result); case Builtin::BI__builtin_launder: return evaluatePointer(E->getArg(0), Result); case Builtin::BIstrchr: @@ -8186,8 +8419,10 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } default: - return visitNonBuiltinCallExpr(E); + break; } + + return visitNonBuiltinCallExpr(E); } static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This, @@ -12838,26 +13073,25 @@ class VoidExprEvaluator bool VisitCallExpr(const CallExpr *E) { switch (E->getBuiltinCallee()) { - default: - return ExprEvaluatorBaseTy::VisitCallExpr(E); case Builtin::BI__assume: case Builtin::BI__builtin_assume: // The argument is not evaluated! return true; + + case Builtin::BI__builtin_operator_delete: + return HandleOperatorDeleteCall(Info, E); + + default: + break; } + + return ExprEvaluatorBaseTy::VisitCallExpr(E); } bool VisitCXXDeleteExpr(const CXXDeleteExpr *E); }; } // end anonymous namespace -static bool hasVirtualDestructor(QualType T) { - if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) - if (CXXDestructorDecl *DD = RD->getDestructor()) - return DD->isVirtual(); - return false; -} - bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) { // We cannot speculatively evaluate a delete expression. if (Info.SpeculativeEvaluationDepth) @@ -12888,49 +13122,12 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) { return true; } - auto PointerAsString = [&] { - APValue Printable; - Pointer.moveInto(Printable); - return Printable.getAsString(Info.Ctx, Arg->getType()); - }; - - DynamicAllocLValue DA = Pointer.Base.dyn_cast(); - if (!DA) { - Info.FFDiag(E, diag::note_constexpr_delete_not_heap_alloc) - << PointerAsString(); - if (Pointer.Base) - NoteLValueLocation(Info, Pointer.Base); + Optional Alloc = CheckDeleteKind( + Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New); + if (!Alloc) return false; - } QualType AllocType = Pointer.Base.getDynamicAllocType(); - Optional Alloc = Info.lookupDynamicAlloc(DA); - if (!Alloc) { - Info.FFDiag(E, diag::note_constexpr_double_delete); - return false; - } - - if (E->isArrayForm() != AllocType->isConstantArrayType()) { - Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch) - << E->isArrayForm() << AllocType; - NoteLValueLocation(Info, Pointer.Base); - return false; - } - - bool Subobject = false; - if (E->isArrayForm()) { - Subobject = Pointer.Designator.Entries.size() != 1 || - Pointer.Designator.Entries[0].getAsArrayIndex() != 0; - } else { - Subobject = Pointer.Designator.MostDerivedPathLength != 0 || - Pointer.Designator.isOnePastTheEnd(); - } - if (Subobject) { - Info.FFDiag(E, diag::note_constexpr_delete_subobject) - << PointerAsString() << Pointer.Designator.isOnePastTheEnd(); - return false; - } - // For the non-array case, the designator must be empty if the static type // does not have a virtual destructor. if (!E->isArrayForm() && Pointer.Designator.Entries.size() != 0 && @@ -12944,7 +13141,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) { (*Alloc)->Value, AllocType)) return false; - if (!Info.HeapAllocs.erase(DA)) { + if (!Info.HeapAllocs.erase(Pointer.Base.dyn_cast())) { // The element was already erased. This means the destructor call also // deleted the object. // FIXME: This probably results in undefined behavior before we get this diff --git a/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp new file mode 100644 index 000000000000..5a39b33a87c5 --- /dev/null +++ b/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s -DNEW=__builtin_operator_new -DDELETE=__builtin_operator_delete +// RUN: %clang_cc1 -std=c++2a -verify %s "-DNEW=operator new" "-DDELETE=operator delete" +// RUN: %clang_cc1 -std=c++2a -verify %s "-DNEW=::operator new" "-DDELETE=::operator delete" + +constexpr bool alloc_from_user_code() { + void *p = NEW(sizeof(int)); // expected-note {{cannot allocate untyped memory in a constant expression; use 'std::allocator::allocate'}} + DELETE(p); + return true; +} +static_assert(alloc_from_user_code()); // expected-error {{constant expression}} expected-note {{in call}} + +namespace std { + using size_t = decltype(sizeof(0)); + // FIXME: It would be preferable to point these notes at the location of the call to allocator<...>::[de]allocate instead + template struct allocator { + constexpr T *allocate(size_t N) { + return (T*)NEW(sizeof(T) * N); // expected-note 3{{heap allocation}} expected-note {{not deallocated}} + } + constexpr void deallocate(void *p) { + DELETE(p); // expected-note 2{{'std::allocator<...>::deallocate' used to delete pointer to object allocated with 'new'}} + } + }; +} + +constexpr bool alloc_via_std_allocator() { + std::allocator alloc; + int *p = alloc.allocate(1); + alloc.deallocate(p); + return true; +} +static_assert(alloc_via_std_allocator()); + +template<> struct std::allocator { + constexpr void *allocate() { return NEW(8); } // expected-note {{cannot allocate memory of function type 'void ()'}} +}; +constexpr void *fn = std::allocator().allocate(); // expected-error {{constant expression}} expected-note {{in call}} + +struct Incomplete; +template<> struct std::allocator { + constexpr void *allocate() { return NEW(8); } // expected-note {{cannot allocate memory of incomplete type 'Incomplete'}} +}; +constexpr void *incomplete = std::allocator().allocate(); // expected-error {{constant expression}} expected-note {{in call}} + +struct WrongSize { char x[5]; }; +static_assert(sizeof(WrongSize) == 5); +template<> struct std::allocator { + constexpr void *allocate() { return NEW(7); } // expected-note {{allocated size 7 is not a multiple of size 5 of element type 'WrongSize'}} +}; +constexpr void *wrong_size = std::allocator().allocate(); // expected-error {{constant expression}} expected-note {{in call}} + +constexpr bool mismatched(int alloc_kind, int dealloc_kind) { + int *p; + switch (alloc_kind) { + case 0: + p = new int; // expected-note {{heap allocation}} + break; + case 1: + p = new int[1]; // expected-note {{heap allocation}} + break; + case 2: + p = std::allocator().allocate(1); + break; + } + switch (dealloc_kind) { + case 0: + delete p; // expected-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} + break; + case 1: + delete[] p; // expected-note {{'delete' used to delete pointer to object allocated with 'std::allocator<...>::allocate'}} + break; + case 2: + std::allocator().deallocate(p); // expected-note 2{{in call}} + break; + } + return true; +} +static_assert(mismatched(0, 2)); // expected-error {{constant expression}} expected-note {{in call}} +static_assert(mismatched(1, 2)); // expected-error {{constant expression}} expected-note {{in call}} +static_assert(mismatched(2, 0)); // expected-error {{constant expression}} expected-note {{in call}} +static_assert(mismatched(2, 1)); // expected-error {{constant expression}} expected-note {{in call}} +static_assert(mismatched(2, 2)); + +constexpr int *escape = std::allocator().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}} +constexpr int leak = (std::allocator().allocate(3), 0); // expected-error {{constant expression}} +constexpr int no_lifetime_start = (*std::allocator().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}} From a706bc7c31fd2ea07ccc981179b565bf2fc7faf5 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 00:39:35 +0000 Subject: [PATCH 09/33] For P0784R7: support placement new-expressions in constant evaluation. For now, we restrict this support to use from within the standard library implementation, since we're required to make parts of the standard library that use placement new work, but not permitted to make uses of placement new from user code work. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373547 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticASTKinds.td | 44 ++++++--- lib/AST/ExprConstant.cpp | 107 ++++++++++++++++++---- lib/AST/Interp/State.h | 1 + test/SemaCXX/cxx2a-constexpr-dynalloc.cpp | 83 +++++++++++++++++ 4 files changed, 201 insertions(+), 34 deletions(-) diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td index 69d30b4eb3f8..63207a0e2254 100644 --- a/include/clang/Basic/DiagnosticASTKinds.td +++ b/include/clang/Basic/DiagnosticASTKinds.td @@ -38,8 +38,8 @@ def note_constexpr_pure_virtual_call : Note< "pure virtual function %q0 called">; def note_constexpr_polymorphic_unknown_dynamic_type : Note< "%select{|||||virtual function called on|dynamic_cast applied to|" - "typeid applied to|destruction of}0 object '%1' whose dynamic type " - "is not constant">; + "typeid applied to|construction of|destruction of}0 object '%1' " + "whose dynamic type is not constant">; def note_constexpr_dynamic_cast_to_reference_failed : Note< "reference dynamic_cast failed: %select{" "static type %1 of operand is a non-public base class of dynamic type %2|" @@ -121,11 +121,12 @@ def note_constexpr_this : Note< "evaluation of a call to a 'constexpr' member function">; def note_constexpr_lifetime_ended : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " - "%select{temporary|variable}1 whose lifetime has ended">; + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 %select{temporary|variable}1 whose " + "%plural{8:storage duration|:lifetime}0 has ended">; def note_constexpr_access_uninit : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to||destruction of}0 " "%select{object outside its lifetime|uninitialized object}1 " "is not allowed in a constant expression">; def note_constexpr_use_uninit_reference : Note< @@ -136,18 +137,19 @@ def note_constexpr_modify_const_type : Note< "in a constant expression">; def note_constexpr_access_volatile_type : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "||}0 " + "|||}0 " "volatile-qualified type %1 is not allowed in a constant expression">; def note_constexpr_access_volatile_obj : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "||}0 " + "|||}0 " "volatile %select{temporary|object %2|member %2}1 is not allowed in " "a constant expression">; def note_constexpr_volatile_here : Note< "volatile %select{temporary created|object declared|member declared}0 here">; def note_constexpr_access_mutable : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "mutable member %1 is not allowed in a constant expression">; def note_constexpr_ltor_non_const_int : Note< "read of non-const variable %0 is not allowed in a constant expression">; @@ -157,35 +159,42 @@ def note_constexpr_ltor_incomplete_type : Note< "read of incomplete type %0 is not allowed in a constant expression">; def note_constexpr_access_null : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "dereferenced null pointer is not allowed in a constant expression">; def note_constexpr_access_past_end : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "dereferenced one-past-the-end pointer is not allowed " "in a constant expression">; def note_constexpr_access_unsized_array : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "element of array without known bound " "is not allowed in a constant expression">; def note_constexpr_access_inactive_union_member : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|" + "construction of subobject of|destruction of}0 " "member %1 of union with %select{active member %3|no active member}2 " "is not allowed in a constant expression">; def note_constexpr_access_static_temporary : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 temporary " + "member call on|dynamic_cast of|typeid applied to|reconstruction of|" + "destruction of}0 temporary " "is not allowed in a constant expression outside the expression that " "created the temporary">; def note_constexpr_access_unreadable_object : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "object '%1' whose value is not known">; def note_constexpr_access_deleted_object : Note< "%select{read of|read of|assignment to|increment of|decrement of|" - "member call on|dynamic_cast of|typeid applied to|destruction of}0 " + "member call on|dynamic_cast of|typeid applied to|construction of|" + "destruction of}0 " "heap allocated object that has been deleted">; def note_constexpr_modify_global : Note< "a constant expression cannot modify an object that is visible outside " @@ -255,6 +264,9 @@ def note_constexpr_bit_cast_indet_dest : Note< def note_constexpr_pseudo_destructor : Note< "pseudo-destructor call is not permitted in constant expressions " "until C++20">; +def note_constexpr_construct_complex_elem : Note< + "construction of individual component of complex number is not yet supported " + "in constant expressions">; def note_constexpr_destroy_complex_elem : Note< "destruction of individual component of complex number is not yet supported " "in constant expressions">; @@ -265,6 +277,8 @@ def note_constexpr_new_non_replaceable : Note< "call to %select{placement|class-specific}0 %1">; def note_constexpr_new_placement : Note< "this placement new expression is not yet supported in constant expressions">; +def note_constexpr_placement_new_wrong_type : Note< + "placement new would change type of storage from %0 to %1">; def note_constexpr_new_negative : Note< "cannot allocate array; evaluated array bound %0 is negative">; def note_constexpr_new_too_large : Note< diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 669acd3a6669..33b0380fd605 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -594,6 +594,13 @@ namespace { Frame *getCaller() const override { return Caller; } SourceLocation getCallLocation() const override { return CallLoc; } const FunctionDecl *getCallee() const override { return Callee; } + + bool isStdFunction() const { + for (const DeclContext *DC = Callee; DC; DC = DC->getParent()) + if (DC->isStdNamespace()) + return true; + return false; + } }; /// Temporarily override 'this'. @@ -1395,6 +1402,7 @@ static bool isModification(AccessKinds AK) { case AK_Assign: case AK_Increment: case AK_Decrement: + case AK_Construct: case AK_Destroy: return true; } @@ -1407,7 +1415,7 @@ static bool isAnyAccess(AccessKinds AK) { /// Is this an access per the C++ definition? static bool isFormalAccess(AccessKinds AK) { - return isAnyAccess(AK) && AK != AK_Destroy; + return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy; } namespace { @@ -3170,8 +3178,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { // Reading an indeterminate value is undefined, but assigning over one is OK. - if (O->isAbsent() || - (O->isIndeterminate() && handler.AccessKind != AK_Assign && + if ((O->isAbsent() && handler.AccessKind != AK_Construct) || + (O->isIndeterminate() && handler.AccessKind != AK_Construct && + handler.AccessKind != AK_Assign && handler.AccessKind != AK_ReadObjectRepresentation)) { if (!Info.checkingPotentialConstantExpression()) Info.FFDiag(E, diag::note_constexpr_access_uninit) @@ -3311,13 +3320,18 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || UnionField->getCanonicalDecl() != Field->getCanonicalDecl()) { - // FIXME: If O->getUnionValue() is absent, report that there's no - // active union member rather than reporting the prior active union - // member. We'll need to fix nullptr_t to not use APValue() as its - // representation first. - Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member) - << handler.AccessKind << Field << !UnionField << UnionField; - return handler.failed(); + if (I == N - 1 && handler.AccessKind == AK_Construct) { + // Placement new onto an inactive union member makes it active. + O->setUnion(Field, APValue()); + } else { + // FIXME: If O->getUnionValue() is absent, report that there's no + // active union member rather than reporting the prior active union + // member. We'll need to fix nullptr_t to not use APValue() as its + // representation first. + Info.FFDiag(E, diag::note_constexpr_access_inactive_union_member) + << handler.AccessKind << Field << !UnionField << UnionField; + return handler.failed(); + } } O = &O->getUnionValue(); } else @@ -8438,14 +8452,23 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { return false; FunctionDecl *OperatorNew = E->getOperatorNew(); - if (!OperatorNew->isReplaceableGlobalAllocationFunction()) { + + bool IsNothrow = false; + bool IsPlacement = false; + if (OperatorNew->isReservedGlobalPlacementOperator() && + Info.CurrentCall->isStdFunction() && !E->isArray()) { + // FIXME Support array placement new. + assert(E->getNumPlacementArgs() == 1); + if (!EvaluatePointer(E->getPlacementArg(0), Result, Info)) + return false; + if (Result.Designator.Invalid) + return false; + IsPlacement = true; + } else if (!OperatorNew->isReplaceableGlobalAllocationFunction()) { Info.FFDiag(E, diag::note_constexpr_new_non_replaceable) << isa(OperatorNew) << OperatorNew; return false; - } - - bool IsNothrow = false; - if (E->getNumPlacementArgs()) { + } else if (E->getNumPlacementArgs()) { // The only new-placement list we support is of the form (std::nothrow). // // FIXME: There is no restriction on this, but it's not clear that any @@ -8543,10 +8566,56 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { "array allocation with non-array new"); } - // Perform the allocation and obtain a pointer to the resulting object. - APValue *Val = Info.createHeapAlloc(E, AllocType, Result); - if (!Val) - return false; + APValue *Val; + if (IsPlacement) { + AccessKinds AK = AK_Construct; + struct FindObjectHandler { + EvalInfo &Info; + const Expr *E; + QualType AllocType; + const AccessKinds AccessKind; + APValue *Value; + + typedef bool result_type; + bool failed() { return false; } + bool found(APValue &Subobj, QualType SubobjType) { + // FIXME: Reject the cases where [basic.life]p8 would not permit the + // old name of the object to be used to name the new object. + if (!Info.Ctx.hasSameUnqualifiedType(SubobjType, AllocType)) { + Info.FFDiag(E, diag::note_constexpr_placement_new_wrong_type) << + SubobjType << AllocType; + return false; + } + Value = &Subobj; + return true; + } + bool found(APSInt &Value, QualType SubobjType) { + Info.FFDiag(E, diag::note_constexpr_construct_complex_elem); + return false; + } + bool found(APFloat &Value, QualType SubobjType) { + Info.FFDiag(E, diag::note_constexpr_construct_complex_elem); + return false; + } + } Handler = {Info, E, AllocType, AK, nullptr}; + + CompleteObject Obj = findCompleteObject(Info, E, AK, Result, AllocType); + if (!Obj || !findSubobject(Info, E, Obj, Result.Designator, Handler)) + return false; + + Val = Handler.Value; + + // [basic.life]p1: + // The lifetime of an object o of type T ends when [...] the storage + // which the object occupies is [...] reused by an object that is not + // nested within o (6.6.2). + *Val = APValue(); + } else { + // Perform the allocation and obtain a pointer to the resulting object. + Val = Info.createHeapAlloc(E, AllocType, Result); + if (!Val) + return false; + } if (ResizedArrayILE) { if (!EvaluateArrayNewInitList(Info, Result, *Val, ResizedArrayILE, diff --git a/lib/AST/Interp/State.h b/lib/AST/Interp/State.h index d02751693f6e..d9a645a3eb3e 100644 --- a/lib/AST/Interp/State.h +++ b/lib/AST/Interp/State.h @@ -32,6 +32,7 @@ enum AccessKinds { AK_MemberCall, AK_DynamicCast, AK_TypeId, + AK_Construct, AK_Destroy, }; diff --git a/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp b/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp index 5a39b33a87c5..23582f2e3026 100644 --- a/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp +++ b/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp @@ -83,3 +83,86 @@ static_assert(mismatched(2, 2)); constexpr int *escape = std::allocator().allocate(3); // expected-error {{constant expression}} expected-note {{pointer to subobject of heap-allocated}} constexpr int leak = (std::allocator().allocate(3), 0); // expected-error {{constant expression}} constexpr int no_lifetime_start = (*std::allocator().allocate(1) = 1); // expected-error {{constant expression}} expected-note {{assignment to object outside its lifetime}} + +void *operator new(std::size_t, void *p) { return p; } +constexpr bool no_placement_new_in_user_code() { // expected-error {{never produces a constant expression}} + int a; + new (&a) int(42); // expected-note {{call to placement 'operator new'}} + return a == 42; +} + +namespace std { + constexpr bool placement_new_in_stdlib() { + int a; + new (&a) int(42); + return a == 42; + } +} +static_assert(std::placement_new_in_stdlib()); + +namespace std { + template + constexpr void construct_at(void *p, Args &&...args) { + new (p) T((Args&&)args...); // #new + } +} + +constexpr bool call_std_construct_at() { + int *p = std::allocator().allocate(3); + std::construct_at(p, 1); + std::construct_at(p + 1, 2); + std::construct_at(p + 2, 3); + bool good = p[0] + p[1] + p[2] == 6; + std::allocator().deallocate(p); + return good; +} +static_assert(call_std_construct_at()); + +constexpr bool bad_construct_at_type() { + int a; + // expected-note@#new {{placement new would change type of storage from 'int' to 'float'}} + std::construct_at(&a, 1.0f); // expected-note {{in call}} + return true; +} +static_assert(bad_construct_at_type()); // expected-error{{}} expected-note {{in call}} + +constexpr bool bad_construct_at_subobject() { + struct X { int a, b; }; + union A { + int a; + X x; + }; + A a = {1}; + // expected-note@#new {{construction of subobject of member 'x' of union with active member 'a' is not allowed in a constant expression}} + std::construct_at(&a.x.a, 1); // expected-note {{in call}} + return true; +} +static_assert(bad_construct_at_subobject()); // expected-error{{}} expected-note {{in call}} + +constexpr bool change_union_member() { + union U { + int a; + int b; + }; + U u = {.a = 1}; + std::construct_at(&u.b, 2); + return u.b == 2; +} +static_assert(change_union_member()); + +int external; +// expected-note@#new {{visible outside}} +static_assert((std::construct_at(&external, 1), true)); // expected-error{{}} expected-note {{in call}} + +constexpr int &&temporary = 0; // expected-note {{created here}} +// expected-note@#new {{construction of temporary is not allowed in a constant expression outside the expression that created the temporary}} +static_assert((std::construct_at(&temporary, 1), true)); // expected-error{{}} expected-note {{in call}} + +constexpr bool construct_after_lifetime() { + int *p = new int; + delete p; + // expected-note@#new {{construction of heap allocated object that has been deleted}} + std::construct_at(p); // expected-note {{in call}} + return true; +} +static_assert(construct_after_lifetime()); // expected-error {{}} expected-note {{in call}} From 6d2412c7e23eb840c4020180ae4de0ac34a25611 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 00:39:37 +0000 Subject: [PATCH 10/33] Mark P0784R7 as complete and start defining its feature-test macro. Note that this only covers the language side of this feature. (The library side has its own feature test macro.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373548 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Frontend/InitPreprocessor.cpp | 1 + test/Lexer/cxx-features.cpp | 4 ++++ www/cxx_status.html | 3 +-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 95d9f62c6087..6a3c898d8c3e 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -543,6 +543,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // C++20 features. if (LangOpts.CPlusPlus2a) { Builder.defineMacro("__cpp_conditional_explicit", "201806L"); + Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); Builder.defineMacro("__cpp_constinit", "201907L"); } if (LangOpts.Char8) diff --git a/test/Lexer/cxx-features.cpp b/test/Lexer/cxx-features.cpp index cda6f888cbce..868ec24a1d9f 100644 --- a/test/Lexer/cxx-features.cpp +++ b/test/Lexer/cxx-features.cpp @@ -34,6 +34,10 @@ #error "wrong value for __cpp_char8_t" #endif +#if check(constexpr_dynamic_alloc, 0, 0, 0, 0, 201907) +#error "wrong value for __cpp_constexpr_dynamic_alloc" +#endif + #if check(constinit, 0, 0, 0, 0, 201907) #error "wrong value for __cpp_constinit" #endif diff --git a/www/cxx_status.html b/www/cxx_status.html index cebe2ed136d3..041d6aa242c7 100755 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -1003,14 +1003,13 @@

C++2a implementation status

P1331R2 - SVN + SVN P1668R1 P0784R7 - Partial Prohibit aggregates with user-declared constructors From bb4498ae6012d84342df3f3acdf55dc1dd9f33e7 Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Thu, 3 Oct 2019 00:41:13 +0000 Subject: [PATCH 11/33] Fixing broken builds due to r373538 due to test that should have been deleted. test/InterfaceStubs/object.cpp should have been deleted. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373549 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/InterfaceStubs/object.cpp | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 test/InterfaceStubs/object.cpp diff --git a/test/InterfaceStubs/object.cpp b/test/InterfaceStubs/object.cpp deleted file mode 100644 index 7f11fe6bf3cb..000000000000 --- a/test/InterfaceStubs/object.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 %s | \ -// RUN: FileCheck -check-prefix=CHECK-TAPI %s - -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ -// RUN: -interface-stub-version=experimental-ifs-v1 %s | \ -// RUN: FileCheck -check-prefix=CHECK-SYMBOLS %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -c %s | llvm-nm - 2>&1 | \ -// RUN: FileCheck -check-prefix=CHECK-SYMBOLS %s - -// CHECK-TAPI: data: { Type: Object, Size: 4 } -// CHECK-SYMBOLS: data -int data = 42; From 40ec03f1e67dc52167cbd0a0644b0d19dced65bb Mon Sep 17 00:00:00 2001 From: Puyan Lotfi Date: Thu, 3 Oct 2019 01:19:51 +0000 Subject: [PATCH 12/33] Fixing broken builds due to r373538, issues with filepath and hexagon toolchain. It appears there are some issues with the hexagon toolchain, and also the file path for the library file. If this doesn't fix the remaining breakages I will attempt a revert. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373552 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/InterfaceStubs/driver-test.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/test/InterfaceStubs/driver-test.c b/test/InterfaceStubs/driver-test.c index e2755b9b9351..12606affb742 100644 --- a/test/InterfaceStubs/driver-test.c +++ b/test/InterfaceStubs/driver-test.c @@ -1,12 +1,19 @@ -// RUN: %clang -x c -o libfoo.so -emit-interface-stubs %s %S/object.c %S/weak.cpp && \ -// RUN: llvm-nm libfoo.so 2>&1 | FileCheck %s +// REQUIRES: x86-registered-target -// RUN: %clang -x c -o libfoo.so -shared %s %S/object.c %S/weak.cpp && \ -// RUN: llvm-nm libfoo.so 2>&1 | FileCheck %s +// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t1.so -emit-interface-stubs %s %S/object.c %S/weak.cpp && \ +// RUN: llvm-nm %t1.so 2>&1 | FileCheck --check-prefix=CHECK-IFS %s -// CHECK-DAG: data -// CHECK-DAG: foo -// CHECK-DAG: strongFunc -// CHECK-DAG: weakFunc +// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t2.so -shared %s %S/object.c %S/weak.cpp && \ +// RUN: llvm-nm %t2.so 2>&1 | FileCheck --check-prefix=CHECK-SO %s -int foo(int bar) { return 42 + 1844; } \ No newline at end of file +// CHECK-IFS-DAG: data +// CHECK-IFS-DAG: foo +// CHECK-IFS-DAG: strongFunc +// CHECK-IFS-DAG: weakFunc + +// CHECK-SO-DAG: data +// CHECK-SO-DAG: foo +// CHECK-SO-DAG: strongFunc +// CHECK-SO-DAG: weakFunc + +int foo(int bar) { return 42 + 1844; } From 5a376e2cb9be9cdb0146b7d5e4598554455bfb53 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 01:20:27 +0000 Subject: [PATCH 13/33] PR43519: don't inject a diagnostic when constant-evaulation of a pointer-to-member call can't determine a callee. We will have produced a diagnostic already if the callee is known to be unevaluatable, and diagnosing here rejects valid code during potential constant expression checking. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373553 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 7 +++++-- test/SemaCXX/constant-expression-cxx11.cpp | 5 +++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 33b0380fd605..908e80123404 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6845,8 +6845,11 @@ class ExprEvaluatorBase HasQualifier = ME->hasQualifier(); } else if (const BinaryOperator *BE = dyn_cast(Callee)) { // Indirect bound member calls ('.*' or '->*'). - Member = dyn_cast_or_null( - HandleMemberPointerAccess(Info, BE, ThisVal, false)); + const ValueDecl *D = + HandleMemberPointerAccess(Info, BE, ThisVal, false); + if (!D) + return false; + Member = dyn_cast(D); if (!Member) return Error(Callee); This = &ThisVal; diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp index bd7094f4d4f2..27ad0f654f56 100644 --- a/test/SemaCXX/constant-expression-cxx11.cpp +++ b/test/SemaCXX/constant-expression-cxx11.cpp @@ -1108,6 +1108,11 @@ namespace MemberPointer { static_assert((int Derived::*)(int Mid<0>::*)&Mid<0>::n != (int Derived::*)(int Mid<1>::*)&Mid<1>::n, ""); static_assert(&Mid<0>::n == (int Mid<0>::*)&Base::n, ""); + + constexpr int apply(const A &a, int (A::*f)() const) { + return (a.*f)(); + } + static_assert(apply(A(2), &A::f) == 5, ""); } namespace ArrayBaseDerived { From c10a6a0580e007991d1e3c7e6cb120c6289d1f7c Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Thu, 3 Oct 2019 02:38:43 +0000 Subject: [PATCH 14/33] Revert 373538 and follow-ups 373549 and 373552. They break tests on (at least) macOS. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373556 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Driver/Action.h | 12 ------ include/clang/Driver/Options.td | 3 -- include/clang/Driver/Phases.h | 3 +- include/clang/Driver/ToolChain.h | 2 - include/clang/Driver/Types.def | 3 +- lib/Driver/Action.cpp | 6 --- lib/Driver/CMakeLists.txt | 1 - lib/Driver/Driver.cpp | 36 ++++------------- lib/Driver/Phases.cpp | 1 - lib/Driver/ToolChain.cpp | 10 ----- lib/Driver/ToolChains/Clang.cpp | 25 ++++++++++-- lib/Driver/ToolChains/InterfaceStubs.cpp | 37 ----------------- lib/Driver/ToolChains/InterfaceStubs.h | 36 ----------------- lib/Driver/Types.cpp | 18 +-------- lib/Frontend/CompilerInvocation.cpp | 23 +++++------ test/InterfaceStubs/bad-format.cpp | 21 +++++----- .../class-template-specialization.cpp | 4 +- test/InterfaceStubs/conflict-type.ifs | 16 -------- test/InterfaceStubs/driver-test.c | 19 --------- test/InterfaceStubs/externstatic.c | 26 +++++++----- test/InterfaceStubs/func.ifs | 40 ------------------- .../function-template-specialization.cpp | 8 ++-- test/InterfaceStubs/inline.c | 33 ++++++++------- test/InterfaceStubs/merge-conflict-test.c | 3 -- test/InterfaceStubs/object-double.c | 5 --- test/InterfaceStubs/object-float.c | 3 -- test/InterfaceStubs/object.c | 7 ---- test/InterfaceStubs/object.cpp | 14 +++++++ test/InterfaceStubs/object.ifs | 28 ------------- .../template-namespace-function.cpp | 2 +- test/InterfaceStubs/weak.cpp | 2 +- test/lit.cfg.py | 4 +- 32 files changed, 111 insertions(+), 340 deletions(-) delete mode 100644 lib/Driver/ToolChains/InterfaceStubs.cpp delete mode 100644 lib/Driver/ToolChains/InterfaceStubs.h delete mode 100644 test/InterfaceStubs/conflict-type.ifs delete mode 100644 test/InterfaceStubs/driver-test.c delete mode 100644 test/InterfaceStubs/func.ifs delete mode 100644 test/InterfaceStubs/merge-conflict-test.c delete mode 100644 test/InterfaceStubs/object-double.c delete mode 100644 test/InterfaceStubs/object-float.c delete mode 100644 test/InterfaceStubs/object.c create mode 100644 test/InterfaceStubs/object.cpp delete mode 100644 test/InterfaceStubs/object.ifs diff --git a/include/clang/Driver/Action.h b/include/clang/Driver/Action.h index c6e90b297835..c1ff0b1a6023 100644 --- a/include/clang/Driver/Action.h +++ b/include/clang/Driver/Action.h @@ -65,7 +65,6 @@ class Action { BackendJobClass, AssembleJobClass, LinkJobClass, - IfsMergeJobClass, LipoJobClass, DsymutilJobClass, VerifyDebugInfoJobClass, @@ -486,17 +485,6 @@ class AssembleJobAction : public JobAction { } }; -class IfsMergeJobAction : public JobAction { - void anchor() override; - -public: - IfsMergeJobAction(ActionList &Inputs, types::ID Type); - - static bool classof(const Action *A) { - return A->getKind() == IfsMergeJobClass; - } -}; - class LinkJobAction : public JobAction { void anchor() override; diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index 7fe99e2013b6..d31c4f46e6b4 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -633,9 +633,6 @@ def emit_llvm : Flag<["-"], "emit-llvm">, Flags<[CC1Option]>, Group; def emit_iterface_stubs : Flag<["-"], "emit-interface-stubs">, Flags<[CC1Option]>, Group, HelpText<"Generate Inteface Stub Files.">; -def emit_merged_ifs : Flag<["-"], "emit-merged-ifs">, - Flags<[CC1Option]>, Group, - HelpText<"Generate Interface Stub Files, emit merged text not binary.">; def iterface_stub_version_EQ : JoinedOrSeparate<["-"], "interface-stub-version=">, Flags<[CC1Option]>; def exported__symbols__list : Separate<["-"], "exported_symbols_list">; def e : JoinedOrSeparate<["-"], "e">, Group; diff --git a/include/clang/Driver/Phases.h b/include/clang/Driver/Phases.h index 63931c00c890..7199c657848c 100644 --- a/include/clang/Driver/Phases.h +++ b/include/clang/Driver/Phases.h @@ -20,8 +20,7 @@ namespace phases { Compile, Backend, Assemble, - Link, - IfsMerge, + Link }; enum { diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 2ba16ab21a92..d6ed87574faa 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -136,13 +136,11 @@ class ToolChain { mutable std::unique_ptr Clang; mutable std::unique_ptr Assemble; mutable std::unique_ptr Link; - mutable std::unique_ptr IfsMerge; mutable std::unique_ptr OffloadBundler; Tool *getClang() const; Tool *getAssemble() const; Tool *getLink() const; - Tool *getIfsMerge() const; Tool *getClangAs() const; Tool *getOffloadBundler() const; diff --git a/include/clang/Driver/Types.def b/include/clang/Driver/Types.def index 79e8d109cd97..a33598e7b7f0 100644 --- a/include/clang/Driver/Types.def +++ b/include/clang/Driver/Types.def @@ -84,8 +84,7 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases // Misc. TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link) -TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge) -TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge) +TYPE("ifs", IFS, INVALID, "ifs", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", phases::Compile, phases::Backend, phases::Assemble, phases::Link) diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index 0187cf981eb5..47b03f6643b8 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -31,7 +31,6 @@ const char *Action::getClassName(ActionClass AC) { case CompileJobClass: return "compiler"; case BackendJobClass: return "backend"; case AssembleJobClass: return "assembler"; - case IfsMergeJobClass: return "interface-stub-merger"; case LinkJobClass: return "linker"; case LipoJobClass: return "lipo"; case DsymutilJobClass: return "dsymutil"; @@ -358,11 +357,6 @@ void AssembleJobAction::anchor() {} AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) : JobAction(AssembleJobClass, Input, OutputType) {} -void IfsMergeJobAction::anchor() {} - -IfsMergeJobAction::IfsMergeJobAction(ActionList &Inputs, types::ID Type) - : JobAction(IfsMergeJobClass, Inputs, Type) {} - void LinkJobAction::anchor() {} LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 64b5d70f42b6..d90c0ff43607 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -66,7 +66,6 @@ add_clang_library(clangDriver ToolChains/WebAssembly.cpp ToolChains/XCore.cpp ToolChains/PPCLinux.cpp - ToolChains/InterfaceStubs.cpp Types.cpp XRayArgs.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index de7ca40d0cd3..5233691be60a 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -274,11 +274,11 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { FinalPhase = phases::Preprocess; - // --precompile only runs up to precompilation. + // --precompile only runs up to precompilation. } else if ((PhaseArg = DAL.getLastArg(options::OPT__precompile))) { FinalPhase = phases::Precompile; - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. + // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_fsyntax_only)) || (PhaseArg = DAL.getLastArg(options::OPT_print_supported_cpus)) || (PhaseArg = DAL.getLastArg(options::OPT_module_file_info)) || @@ -286,23 +286,20 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_rewrite_objc)) || (PhaseArg = DAL.getLastArg(options::OPT_rewrite_legacy_objc)) || (PhaseArg = DAL.getLastArg(options::OPT__migrate)) || + (PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs)) || (PhaseArg = DAL.getLastArg(options::OPT__analyze)) || (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; - // clang interface stubs - } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_iterface_stubs))) { - FinalPhase = phases::IfsMerge; - - // -S only runs up to the backend. + // -S only runs up to the backend. } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; - // -c compilation only runs up to the assembler. + // -c compilation only runs up to the assembler. } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; - // Otherwise do everything. + // Otherwise do everything. } else FinalPhase = phases::Link; @@ -3326,7 +3323,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, // Construct the actions to perform. HeaderModulePrecompileJobAction *HeaderModuleAction = nullptr; ActionList LinkerInputs; - ActionList MergerInputs; for (auto &I : Inputs) { types::ID InputType = I.first; @@ -3364,17 +3360,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, break; } - // TODO: Consider removing this because the merged may not end up being - // the final Phase in the pipeline. Perhaps the merged could just merge - // and then pass an artifact of some sort to the Link Phase. - // Queue merger inputs. - if (Phase == phases::IfsMerge) { - assert(Phase == PL.back() && "merging must be final compilation step."); - MergerInputs.push_back(Current); - Current = nullptr; - break; - } - // Each precompiled header file after a module file action is a module // header of that same module file, rather than being compiled to a // separate PCH. @@ -3424,11 +3409,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back(LA); } - // Add an interface stubs merge action if necessary. - if (!MergerInputs.empty()) - Actions.push_back( - C.MakeAction(MergerInputs, types::TY_Image)); - // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { @@ -3465,8 +3445,6 @@ Action *Driver::ConstructPhaseAction( switch (Phase) { case phases::Link: llvm_unreachable("link action invalid here."); - case phases::IfsMerge: - llvm_unreachable("ifsmerge action invalid here."); case phases::Preprocess: { types::ID OutputTy; // -M and -MM specify the dependency file name by altering the output type, @@ -3531,7 +3509,7 @@ Action *Driver::ConstructPhaseAction( if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction(Input, types::TY_Nothing); if (Args.hasArg(options::OPT_emit_iterface_stubs)) - return C.MakeAction(Input, types::TY_IFS_CPP); + return C.MakeAction(Input, types::TY_IFS); return C.MakeAction(Input, types::TY_LLVM_BC); } case phases::Backend: { diff --git a/lib/Driver/Phases.cpp b/lib/Driver/Phases.cpp index 01598c59bd9e..5b776c63f713 100644 --- a/lib/Driver/Phases.cpp +++ b/lib/Driver/Phases.cpp @@ -20,7 +20,6 @@ const char *phases::getPhaseName(ID Id) { case Backend: return "backend"; case Assemble: return "assembler"; case Link: return "linker"; - case IfsMerge: return "ifsmerger"; } llvm_unreachable("Invalid phase id."); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index db2497a10856..4379da99d07b 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -10,7 +10,6 @@ #include "InputInfo.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" -#include "ToolChains/InterfaceStubs.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -280,12 +279,6 @@ Tool *ToolChain::getLink() const { return Link.get(); } -Tool *ToolChain::getIfsMerge() const { - if (!IfsMerge) - IfsMerge.reset(new tools::ifstool::Merger(*this)); - return IfsMerge.get(); -} - Tool *ToolChain::getOffloadBundler() const { if (!OffloadBundler) OffloadBundler.reset(new tools::OffloadBundler(*this)); @@ -297,9 +290,6 @@ Tool *ToolChain::getTool(Action::ActionClass AC) const { case Action::AssembleJobClass: return getAssemble(); - case Action::IfsMergeJobClass: - return getIfsMerge(); - case Action::LinkJobClass: return getLink(); diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 26e8bc60bfa4..8628741f7dae 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -3683,15 +3683,32 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } else if (JA.getType() == types::TY_LLVM_BC || JA.getType() == types::TY_LTO_BC) { CmdArgs.push_back("-emit-llvm-bc"); - } else if (JA.getType() == types::TY_IFS || - JA.getType() == types::TY_IFS_CPP) { + } else if (JA.getType() == types::TY_IFS) { StringRef ArgStr = Args.hasArg(options::OPT_iterface_stub_version_EQ) ? Args.getLastArgValue(options::OPT_iterface_stub_version_EQ) - : "experimental-ifs-v1"; + : ""; + StringRef StubFormat = + llvm::StringSwitch(ArgStr) + .Case("experimental-ifs-v1", "experimental-ifs-v1") + .Default(""); + + if (StubFormat.empty()) { + std::string ErrorMessage = + "Invalid interface stub format: " + ArgStr.str() + + ((ArgStr == "experimental-yaml-elf-v1" || + ArgStr == "experimental-tapi-elf-v1") + ? " is deprecated." + : "."); + D.Diag(diag::err_drv_invalid_value) + << "Must specify a valid interface stub format type, ie: " + "-interface-stub-version=experimental-ifs-v1" + << ErrorMessage; + } + CmdArgs.push_back("-emit-interface-stubs"); CmdArgs.push_back( - Args.MakeArgString(Twine("-interface-stub-version=") + ArgStr.str())); + Args.MakeArgString(Twine("-interface-stub-version=") + StubFormat)); } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); } else if (JA.getType() == types::TY_AST) { diff --git a/lib/Driver/ToolChains/InterfaceStubs.cpp b/lib/Driver/ToolChains/InterfaceStubs.cpp deleted file mode 100644 index 6677843b2c53..000000000000 --- a/lib/Driver/ToolChains/InterfaceStubs.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "InterfaceStubs.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" - -namespace clang { -namespace driver { -namespace tools { -namespace ifstool { -void Merger::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - const char *LinkingOutput) const { - std::string Merger = getToolChain().GetProgramPath(getShortName()); - llvm::opt::ArgStringList CmdArgs; - CmdArgs.push_back("-action"); - CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) - ? "write-ifs" - : "write-bin"); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - for (const auto &Input : Inputs) - CmdArgs.push_back(Input.getFilename()); - C.addCommand(std::make_unique(JA, *this, Args.MakeArgString(Merger), - CmdArgs, Inputs)); -} -} // namespace ifstool -} // namespace tools -} // namespace driver -} // namespace clang diff --git a/lib/Driver/ToolChains/InterfaceStubs.h b/lib/Driver/ToolChains/InterfaceStubs.h deleted file mode 100644 index 4afa73701a4c..000000000000 --- a/lib/Driver/ToolChains/InterfaceStubs.h +++ /dev/null @@ -1,36 +0,0 @@ -//===--- InterfaceStubs.cpp - Base InterfaceStubs Implementations C++ ---===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H - -#include "clang/Driver/Tool.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { -namespace ifstool { -class LLVM_LIBRARY_VISIBILITY Merger : public Tool { -public: - Merger(const ToolChain &TC) : Tool("IFS::Merger", "llvm-ifs", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace ifstool -} // end namespace tools -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_IFS_H diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 6241fac0c85a..da01e1acfcaa 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -269,7 +269,6 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("lib", TY_Object) .Case("mii", TY_PP_ObjCXX) .Case("obj", TY_Object) - .Case("ifs", TY_IFS) .Case("pch", TY_PCH) .Case("pcm", TY_ModuleFile) .Case("c++m", TY_CXXModule) @@ -320,22 +319,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::copy_if(PhaseList, std::back_inserter(P), [](phases::ID Phase) { return Phase <= phases::Precompile; }); - // Treat Interface Stubs like its own compilation mode. - else if (DAL.getLastArg(options::OPT_emit_iterface_stubs)) { - llvm::SmallVector IfsModePhaseList; - llvm::SmallVector &PL = PhaseList; - phases::ID LastPhase = phases::IfsMerge; - if (Id != types::TY_IFS) { - if (DAL.hasArg(options::OPT_c)) - LastPhase = phases::Compile; - PL = IfsModePhaseList; - types::getCompilationPhases(types::TY_IFS_CPP, PL); - } - llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { - return Phase <= LastPhase; - }); - } - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. else if (DAL.getLastArg(options::OPT_fsyntax_only) || DAL.getLastArg(options::OPT_print_supported_cpus) || @@ -344,6 +327,7 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, DAL.getLastArg(options::OPT_rewrite_objc) || DAL.getLastArg(options::OPT_rewrite_legacy_objc) || DAL.getLastArg(options::OPT__migrate) || + DAL.getLastArg(options::OPT_emit_iterface_stubs) || DAL.getLastArg(options::OPT__analyze) || DAL.getLastArg(options::OPT_emit_ast)) llvm::copy_if(PhaseList, std::back_inserter(P), diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 6fc8afcf3c66..61a2c07890fc 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1734,25 +1734,24 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, StringRef ArgStr = Args.hasArg(OPT_iterface_stub_version_EQ) ? Args.getLastArgValue(OPT_iterface_stub_version_EQ) - : "experimental-ifs-v1"; - if (ArgStr == "experimental-yaml-elf-v1" || - ArgStr == "experimental-tapi-elf-v1") { + : ""; + llvm::Optional ProgramAction = + llvm::StringSwitch>(ArgStr) + .Case("experimental-ifs-v1", frontend::GenerateInterfaceIfsExpV1) + .Default(llvm::None); + if (!ProgramAction) { std::string ErrorMessage = "Invalid interface stub format: " + ArgStr.str() + - " is deprecated."; - Diags.Report(diag::err_drv_invalid_value) - << "Must specify a valid interface stub format type, ie: " - "-interface-stub-version=experimental-ifs-v1" - << ErrorMessage; - } else if (ArgStr != "experimental-ifs-v1") { - std::string ErrorMessage = - "Invalid interface stub format: " + ArgStr.str() + "."; + ((ArgStr == "experimental-yaml-elf-v1" || + ArgStr == "experimental-tapi-elf-v1") + ? " is deprecated." + : "."); Diags.Report(diag::err_drv_invalid_value) << "Must specify a valid interface stub format type, ie: " "-interface-stub-version=experimental-ifs-v1" << ErrorMessage; } else { - Opts.ProgramAction = frontend::GenerateInterfaceIfsExpV1; + Opts.ProgramAction = *ProgramAction; } break; } diff --git a/test/InterfaceStubs/bad-format.cpp b/test/InterfaceStubs/bad-format.cpp index 4d51ac867eb2..f13ea2fc76b3 100644 --- a/test/InterfaceStubs/bad-format.cpp +++ b/test/InterfaceStubs/bad-format.cpp @@ -1,25 +1,28 @@ -// RUN: not %clang -emit-interface-stubs -interface-stub-version=bad-format %s 2>&1 | \ -// RUN: FileCheck %s +// REQUIRES: x86-registered-target +// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=bar-format %s 2>&1 | FileCheck %s -// RUN: not %clang -emit-interface-stubs -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ +// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-TAPI-DEPRECATED %s -// RUN: not %clang -emit-interface-stubs -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ +// RUN: not %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-YAML-DEPRECATED %s -// RUN: not %clang -emit-interface-stubs -interface-stub-version=bad-format %s 2>&1 | \ -// RUN: FileCheck %s +// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=bar-format %s 2>&1 | FileCheck %s -// RUN: not %clang -emit-interface-stubs \ +// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-tapi-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-TAPI-DEPRECATED %s -// RUN: not %clang -emit-interface-stubs \ +// RUN: not %clang_cc1 -target x86_64-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-yaml-elf-v1 %s 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-YAML-DEPRECATED %s // CHECK: error: invalid value -// CHECK: 'Invalid interface stub format: bad-format.' in 'Must specify a +// CHECK: 'Invalid interface stub format: bar-format.' in 'Must specify a // CHECK: valid interface stub format type, ie: // CHECK: -interface-stub-version=experimental-ifs-v1' diff --git a/test/InterfaceStubs/class-template-specialization.cpp b/test/InterfaceStubs/class-template-specialization.cpp index 0a68d3f1f117..29e459390495 100644 --- a/test/InterfaceStubs/class-template-specialization.cpp +++ b/test/InterfaceStubs/class-template-specialization.cpp @@ -1,9 +1,9 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck -check-prefix=CHECK-TAPI %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck -check-prefix=CHECK-TAPI2 %s // RUN: %clang -target x86_64-unknown-linux-gnu -o - -c %s | \ diff --git a/test/InterfaceStubs/conflict-type.ifs b/test/InterfaceStubs/conflict-type.ifs deleted file mode 100644 index aaa04775e317..000000000000 --- a/test/InterfaceStubs/conflict-type.ifs +++ /dev/null @@ -1,16 +0,0 @@ -# RUN: not %clang -emit-merged-ifs -emit-interface-stubs -o - %s %S/func.ifs 2>&1 | \ -# RUN: FileCheck %s --check-prefixes=CHECK-IFS - -# Here we are testing to see if two symbols with identical names will fail to -# merge in conflict due to mismatched types. -# CHECK-IFS: error: Interface Stub: Type Mismatch for a. -# CHECK-IFS-NEXT: Filename: -# CHECK-IFS-NEXT: Type Values: Object Func - ---- !experimental-ifs-v1 -IfsVersion: 1.0 -Triple: x86_64-linux-gnu -ObjectFileFormat: ELF -Symbols: - a: { Type: Object, Size: 1 } -... diff --git a/test/InterfaceStubs/driver-test.c b/test/InterfaceStubs/driver-test.c deleted file mode 100644 index 12606affb742..000000000000 --- a/test/InterfaceStubs/driver-test.c +++ /dev/null @@ -1,19 +0,0 @@ -// REQUIRES: x86-registered-target - -// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t1.so -emit-interface-stubs %s %S/object.c %S/weak.cpp && \ -// RUN: llvm-nm %t1.so 2>&1 | FileCheck --check-prefix=CHECK-IFS %s - -// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t2.so -shared %s %S/object.c %S/weak.cpp && \ -// RUN: llvm-nm %t2.so 2>&1 | FileCheck --check-prefix=CHECK-SO %s - -// CHECK-IFS-DAG: data -// CHECK-IFS-DAG: foo -// CHECK-IFS-DAG: strongFunc -// CHECK-IFS-DAG: weakFunc - -// CHECK-SO-DAG: data -// CHECK-SO-DAG: foo -// CHECK-SO-DAG: strongFunc -// CHECK-SO-DAG: weakFunc - -int foo(int bar) { return 42 + 1844; } diff --git a/test/InterfaceStubs/externstatic.c b/test/InterfaceStubs/externstatic.c index 37d5b7db19a2..bc1aef477bcd 100644 --- a/test/InterfaceStubs/externstatic.c +++ b/test/InterfaceStubs/externstatic.c @@ -1,20 +1,24 @@ -// RUN: %clang -c -DSTORAGE="extern" -o - -emit-interface-stubs -std=c99 -xc %s | \ +// REQUIRES: x86-registered-target +// RUN: %clang -DSTORAGE="extern" -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-EXTERN %s - -// RUN: %clang -DSTORAGE="extern" -O0 -o - -c -std=c99 \ +// RUN: %clang -DSTORAGE="extern" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ // RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-EXTERN %s -// RUN: %clang -c -DSTORAGE="extern" -o - -emit-interface-stubs -std=c99 -xc %s | \ -// RUN: FileCheck -check-prefix=CHECK-EXTERN2 %s - -// RUN: %clang -DSTORAGE="extern" -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ +// RUN: %clang -DSTORAGE="extern" -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-EXTERN2 %s +// RUN: %clang -DSTORAGE="extern" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ +// RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-EXTERN2 %s -// RUN: %clang -c -DSTORAGE="static" -o - -emit-interface-stubs -std=c99 -xc %s | \ -// RUN: FileCheck -check-prefix=CHECK-STATIC %s - -// RUN: %clang -DSTORAGE="static" -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ +// RUN: %clang -DSTORAGE="static" -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-STATIC %s +// RUN: %clang -DSTORAGE="static" -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ +// RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-STATIC %s // CHECK-EXTERN-NOT: foo // CHECK-STATIC-NOT: foo diff --git a/test/InterfaceStubs/func.ifs b/test/InterfaceStubs/func.ifs deleted file mode 100644 index d115523bfda4..000000000000 --- a/test/InterfaceStubs/func.ifs +++ /dev/null @@ -1,40 +0,0 @@ -# RUN: %clang -emit-interface-stubs -o - %s %S/object.ifs -emit-merged-ifs | \ -# RUN: FileCheck %s --check-prefixes=CHECK-IFS - -# RUN: %clang -emit-interface-stubs -o - %s %S/object.ifs | llvm-readelf --all | \ -# RUN: FileCheck %s --check-prefixes=CHECK-ELF - -# RUN: %clang -emit-interface-stubs -o - %s %s -emit-merged-ifs | \ -# RUN: FileCheck %s --check-prefixes=CHECK-MERGE-IFS - -# CHECK-IFS: --- !experimental-ifs-v1 -# CHECK-IFS-NEXT: IfsVersion: 1.0 -# CHECK-IFS-NEXT: Triple: x86_64-linux-gnu -# CHECK-IFS-NEXT: ObjectFileFormat: ELF -# CHECK-IFS-NEXT: Symbols: -# CHECK-IFS-DAG: a: { Type: Func } -# CHECK-IFS-DAG: b: { Type: Object, Size: 4 } -# CHECK-IFS: ... - -# CHECK-ELF: ELF Header: -# CHECK-ELF: Class: ELF64 -# CHECK-ELF: Type: DYN (Shared object file) -# CHECK-ELF: FUNC GLOBAL DEFAULT 1 a -# CHECK-ELF: OBJECT GLOBAL DEFAULT 1 b - -# Here we are testing to see if two identical symbols will merge. -# CHECK-MERGE-IFS: --- !experimental-ifs-v1 -# CHECK-MERGE-IFS-NEXT: IfsVersion: 1.0 -# CHECK-MERGE-IFS-NEXT: Triple: x86_64-linux-gnu -# CHECK-MERGE-IFS-NEXT: ObjectFileFormat: ELF -# CHECK-MERGE-IFS-NEXT: Symbols: -# CHECK-MERGE-IFS-NEXT: a: { Type: Func } -# CHECK-MERGE-IFS-NEXT: ... - ---- !experimental-ifs-v1 -IfsVersion: 1.0 -Triple: x86_64-linux-gnu -ObjectFileFormat: ELF -Symbols: - a: { Type: Func } -... diff --git a/test/InterfaceStubs/function-template-specialization.cpp b/test/InterfaceStubs/function-template-specialization.cpp index f6ec64bcd916..f6e5c87e7f44 100644 --- a/test/InterfaceStubs/function-template-specialization.cpp +++ b/test/InterfaceStubs/function-template-specialization.cpp @@ -1,15 +1,13 @@ // REQUIRES: x86-registered-target - -// TODO: Fix the case in llvm-ifs where it crashes on an empty Symbols list. -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -c \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | FileCheck %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 \ // RUN: -DUSE_TEMPLATE_FUNCTION=1 %s | \ // RUN: FileCheck -check-prefix=CHECK-USES-TEMPLATE-FUNCTION %s -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 \ // RUN: -DSPECIALIZE_TEMPLATE_FUNCTION=1 %s | \ // RUN: FileCheck -check-prefix=CHECK-SPECIALIZES-TEMPLATE-FUNCTION %s diff --git a/test/InterfaceStubs/inline.c b/test/InterfaceStubs/inline.c index 06a58c4c1bea..e32b4e100960 100644 --- a/test/InterfaceStubs/inline.c +++ b/test/InterfaceStubs/inline.c @@ -1,32 +1,37 @@ // REQUIRES: x86-registered-target -// RUN: %clang -c -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs -std=gnu89 -xc %s | \ +// RUN: %clang -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=gnu89 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-GNU %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -O0 -o - -c \ // RUN: -std=gnu89 -xc %s | llvm-nm - | FileCheck -check-prefix=CHECK-GNU %s -// RUN: %clang -c -DINLINE="__attribute__((always_inline))" \ -// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -xc %s | \ +// RUN: %clang -DINLINE="__attribute__((always_inline))" \ +// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-GNU %s // RUN: %clang -DINLINE="__attribute__((always_inline))" \ // RUN: -target x86_64-linux-gnu -O0 -o - -c -xc %s | \ // RUN: llvm-nm - | FileCheck -check-prefix=CHECK-GNU %s -// RUN: %clang -c -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs -std=c99 -xc %s | \ +// RUN: %clang -DINLINE=inline -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-STD %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -O0 -o - -c -std=c99 \ // RUN: -xc %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-STD %s -// RUN: %clang -c -DINLINE="__attribute__((noinline))" \ -// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -std=c99 -xc %s | \ +// RUN: %clang -DINLINE="__attribute__((noinline))" \ +// RUN: -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-NOINLINE %s // RUN: %clang -DINLINE="__attribute__((noinline))" -target x86_64-linux-gnu \ // RUN: -O0 -o - -c -std=c99 -xc %s | llvm-nm - 2>&1 | \ // RUN: FileCheck -check-prefix=CHECK-NOINLINE %s -// RUN: %clang -c -DINLINE="static" -target x86_64-unknown-linux-gnu -o - \ -// RUN: -emit-interface-stubs -std=c99 -xc %s | \ +// RUN: %clang -DINLINE="static" -target x86_64-unknown-linux-gnu -o - \ +// RUN: -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 -std=c99 -xc %s | \ // RUN: FileCheck -check-prefix=CHECK-STATIC %s // RUN: %clang -DINLINE="static" -target x86_64-linux-gnu -O0 -o - -c \ // RUN: -std=c99 -xc %s | llvm-nm - 2>&1 | \ @@ -45,12 +50,12 @@ INLINE int foo() { return var; } -// RUN: %clang -c -DINLINE=inline -target x86_64-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ +// RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ +// RUN: -emit-interface-stubs -interface-stub-version=experimental-ifs-v1 \ // RUN: -std=gnu89 -xc %s | FileCheck -check-prefix=CHECK-TAPI %s -// RUN: %clang -c -DINLINE=inline -target x86_64-linux-gnu -o - \ -// RUN: -emit-interface-stubs \ +// RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ +// RUN: -emit-interface-stubs -interface-stub-version=experimental-ifs-v1 \ // RUN: -std=gnu89 -xc %s | FileCheck -check-prefix=CHECK-SYMBOLS %s // RUN: %clang -DINLINE=inline -target x86_64-linux-gnu -o - \ // RUN: -c -std=gnu89 -xc %s | llvm-nm - 2>&1 | \ diff --git a/test/InterfaceStubs/merge-conflict-test.c b/test/InterfaceStubs/merge-conflict-test.c deleted file mode 100644 index 2d006148ba46..000000000000 --- a/test/InterfaceStubs/merge-conflict-test.c +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: not %clang -o libfoo.so -emit-interface-stubs %s %S/driver-test.c 2>&1 | FileCheck %s -// CHECK: error: Interface Stub: Type Mismatch -int foo; \ No newline at end of file diff --git a/test/InterfaceStubs/object-double.c b/test/InterfaceStubs/object-double.c deleted file mode 100644 index c6d2b61a4d9e..000000000000 --- a/test/InterfaceStubs/object-double.c +++ /dev/null @@ -1,5 +0,0 @@ -// RUN: not %clang -o - -emit-interface-stubs %s %S/object.c 2>&1 | FileCheck %s -// Need to encode more type info or weak vs strong symbol resolution in llvm-ifs -// XFAIL: * -// CHECK: error: Interface Stub: Size Mismatch -float data = 42.0; \ No newline at end of file diff --git a/test/InterfaceStubs/object-float.c b/test/InterfaceStubs/object-float.c deleted file mode 100644 index 6dd056bb852e..000000000000 --- a/test/InterfaceStubs/object-float.c +++ /dev/null @@ -1,3 +0,0 @@ -// RUN: not %clang -o - -emit-interface-stubs %s %S/object.c 2>&1 | FileCheck %s -// CHECK: error: Interface Stub: Size Mismatch -double data = 42.0; \ No newline at end of file diff --git a/test/InterfaceStubs/object.c b/test/InterfaceStubs/object.c deleted file mode 100644 index b07bea930e56..000000000000 --- a/test/InterfaceStubs/object.c +++ /dev/null @@ -1,7 +0,0 @@ -// RUN: %clang -c -o - -emit-interface-stubs %s | FileCheck -check-prefix=CHECK-TAPI %s -// RUN: %clang -c -o - -emit-interface-stubs %s | FileCheck -check-prefix=CHECK-SYMBOLS %s -// RUN: %clang -c -o - %s | llvm-nm - 2>&1 | FileCheck -check-prefix=CHECK-SYMBOLS %s - -// CHECK-TAPI: data: { Type: Object, Size: 4 } -// CHECK-SYMBOLS: data -int data = 42; diff --git a/test/InterfaceStubs/object.cpp b/test/InterfaceStubs/object.cpp new file mode 100644 index 000000000000..7f11fe6bf3cb --- /dev/null +++ b/test/InterfaceStubs/object.cpp @@ -0,0 +1,14 @@ +// REQUIRES: x86-registered-target +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 %s | \ +// RUN: FileCheck -check-prefix=CHECK-TAPI %s + +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ +// RUN: -interface-stub-version=experimental-ifs-v1 %s | \ +// RUN: FileCheck -check-prefix=CHECK-SYMBOLS %s +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -c %s | llvm-nm - 2>&1 | \ +// RUN: FileCheck -check-prefix=CHECK-SYMBOLS %s + +// CHECK-TAPI: data: { Type: Object, Size: 4 } +// CHECK-SYMBOLS: data +int data = 42; diff --git a/test/InterfaceStubs/object.ifs b/test/InterfaceStubs/object.ifs deleted file mode 100644 index 7dc1134bac93..000000000000 --- a/test/InterfaceStubs/object.ifs +++ /dev/null @@ -1,28 +0,0 @@ -# RUN: %clang -emit-interface-stubs -o - -emit-merged-ifs %s | \ -# RUN: FileCheck %s --check-prefixes=CHECK-IFS - -# RUN: %clang -emit-interface-stubs -o - %s | llvm-readelf --all | \ -# RUN: FileCheck %s --check-prefixes=CHECK-ELF - -# CHECK-IFS: --- !experimental-ifs-v1 -# CHECK-IFS-NEXT: IfsVersion: 1.0 -# CHECK-IFS-NEXT: Triple: x86_64-linux-gnu -# CHECK-IFS-NEXT: ObjectFileFormat: ELF -# CHECK-IFS-NEXT: Symbols: -# CHECK-IFS-NEXT: b: { Type: Object, Size: 4 } -# CHECK-IFS-NEXT: ... - -# CHECK-ELF: ELF Header: -# CHECK-ELF: Class: ELF64 -# CHECK-ELF: Data: 2's complement, little endian -# CHECK-ELF: Type: DYN (Shared object file) -# CHECK-ELF-NOT: FUNC GLOBAL DEFAULT 1 a -# CHECK-ELF: OBJECT GLOBAL DEFAULT 1 b - ---- !experimental-ifs-v1 -IfsVersion: 1.0 -Triple: x86_64-linux-gnu -ObjectFileFormat: ELF -Symbols: - b: { Type: Object, Size: 4 } -... diff --git a/test/InterfaceStubs/template-namespace-function.cpp b/test/InterfaceStubs/template-namespace-function.cpp index ad8606757c9e..4956525b4060 100644 --- a/test/InterfaceStubs/template-namespace-function.cpp +++ b/test/InterfaceStubs/template-namespace-function.cpp @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-unknown-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck %s diff --git a/test/InterfaceStubs/weak.cpp b/test/InterfaceStubs/weak.cpp index e1c2c232a9d8..13b7e5aa2938 100644 --- a/test/InterfaceStubs/weak.cpp +++ b/test/InterfaceStubs/weak.cpp @@ -1,5 +1,5 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-linux-gnu -o - -emit-interface-stubs -emit-merged-ifs \ +// RUN: %clang -target x86_64-linux-gnu -o - -emit-interface-stubs \ // RUN: -interface-stub-version=experimental-ifs-v1 %s | \ // RUN: FileCheck %s diff --git a/test/lit.cfg.py b/test/lit.cfg.py index 1ffb6d094d72..9ffe30ec50d5 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -26,7 +26,7 @@ # suffixes: A list of file extensions to treat as test files. config.suffixes = ['.c', '.cpp', '.cppm', '.m', '.mm', '.cu', - '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs', '.ifs'] + '.ll', '.cl', '.s', '.S', '.modulemap', '.test', '.rs'] # excludes: A list of directories to exclude from the testsuite. The 'Inputs' # subdirectories contain auxiliary inputs for various tests in their parent @@ -61,7 +61,7 @@ tool_dirs = [config.clang_tools_dir, config.llvm_tools_dir] tools = [ - 'c-index-test', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', 'llvm-ifs', + 'c-index-test', 'clang-diff', 'clang-format', 'clang-tblgen', 'opt', ToolSubst('%clang_extdef_map', command=FindTool( 'clang-extdef-mapping'), unresolved='ignore'), ] From aba8d4b444c5c767187edf2d99faf98b71ad2dc0 Mon Sep 17 00:00:00 2001 From: Yaxun Liu Date: Thu, 3 Oct 2019 03:27:43 +0000 Subject: [PATCH 15/33] [HIP] Support -emit-llvm for device compilation Sometimes it is useful to compile HIP device code to LLVM BC. It is not convenient to use clang -cc1 since there are lots of options needed. This patch allows clang driver to compile HIP device code to LLVM BC with -emit-llvm -c. Differential Revision: https://reviews.llvm.org/D68284 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373561 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/Driver.cpp | 10 ++++- test/Driver/hip-device-compile.hip | 72 ++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test/Driver/hip-device-compile.hip diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 5233691be60a..8fc3db8c8348 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2312,6 +2312,8 @@ class OffloadingActionBuilder final { /// compilation. bool CompileHostOnly = false; bool CompileDeviceOnly = false; + bool EmitLLVM = false; + bool EmitAsm = false; /// List of GPU architectures to use in this compilation. SmallVector GpuArchList; @@ -2478,6 +2480,8 @@ class OffloadingActionBuilder final { CompileDeviceOnly = PartialCompilationArg && PartialCompilationArg->getOption().matches( options::OPT_cuda_device_only); + EmitLLVM = Args.getLastArg(options::OPT_emit_llvm); + EmitAsm = Args.getLastArg(options::OPT_S); // Collect all cuda_gpu_arch parameters, removing duplicates. std::set GpuArchs; @@ -2664,7 +2668,8 @@ class OffloadingActionBuilder final { assert(!CompileHostOnly && "Not expecting CUDA actions in host-only compilation."); - if (!Relocatable && CurPhase == phases::Backend) { + if (!Relocatable && CurPhase == phases::Backend && !EmitLLVM && + !EmitAsm) { // If we are in backend phase, we attempt to generate the fat binary. // We compile each arch to IR and use a link action to generate code // object containing ISA. Then we use a special "link" action to create @@ -2732,7 +2737,8 @@ class OffloadingActionBuilder final { A = C.getDriver().ConstructPhaseAction(C, Args, CurPhase, A, AssociatedOffloadKind); - return ABRT_Success; + return (CompileDeviceOnly && CurPhase == FinalPhase) ? ABRT_Ignore_Host + : ABRT_Success; } void appendLinkDependences(OffloadAction::DeviceDependences &DA) override { diff --git a/test/Driver/hip-device-compile.hip b/test/Driver/hip-device-compile.hip new file mode 100644 index 000000000000..b6f1f1cf218e --- /dev/null +++ b/test/Driver/hip-device-compile.hip @@ -0,0 +1,72 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// If -emit-llvm and/or -S is used in device only compilation, +// the output should not be bundled. + +// RUN: %clang -c -emit-llvm --cuda-device-only -### -target x86_64-linux-gnu \ +// RUN: -o a.bc -x hip --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,BC %s + +// RUN: %clang -c -S -emit-llvm --cuda-device-only -### -target x86_64-linux-gnu \ +// RUN: -o a.ll -x hip --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,LL %s + +// RUN: %clang -c -S --cuda-device-only -### -target x86_64-linux-gnu \ +// RUN: -o a.s -x hip --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: 2>&1 | FileCheck -check-prefixes=CHECK,ASM %s + +// CHECK: {{".*clang.*"}} "-cc1" "-triple" "amdgcn-amd-amdhsa" +// CHECK-SAME: "-aux-triple" "x86_64-unknown-linux-gnu" +// BC-SAME: "-emit-llvm-bc" +// LL-SAME: "-emit-llvm" +// ASM-NOT: "-emit-llvm" +// CHECK-SAME: "-main-file-name" "a.cu" {{.*}} "-target-cpu" "gfx900" +// CHECK-SAME: "-fcuda-is-device" +// CHECK-SAME: {{".*lib1.bc"}} +// BC-SAME: "-o" "a.bc" +// LL-SAME: "-o" "a.ll" +// ASM-SAME: "-o" "a.s" +// CHECK-SAME: {{".*a.cu"}} + +// CHECK-NOT: {{"*.llvm-link"}} +// CHECK-NOT: {{".*opt"}} +// CHECK-NOT: {{".*llc"}} +// CHECK-NOT: {{".*lld"}} +// CHECK-NOT: {{".*clang-offload-bundler"}} +// CHECK-NOT: {{".*ld.*"}} + +// If neither -emit-llvm nor -S is used in device only compilation, +// the output should be bundled. + +// RUN: %clang -c --cuda-device-only -### -target x86_64-linux-gnu \ +// RUN: -o a.s -x hip --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: 2>&1 | FileCheck -check-prefixes=BUNDLE %s + +// RUN: %clang --cuda-device-only -### -target x86_64-linux-gnu \ +// RUN: -o a.s -x hip --cuda-gpu-arch=gfx900 \ +// RUN: --hip-device-lib=lib1.bc \ +// RUN: --hip-device-lib-path=%S/Inputs/hip_multiple_inputs/lib1 \ +// RUN: %S/Inputs/hip_multiple_inputs/a.cu \ +// RUN: 2>&1 | FileCheck -check-prefixes=BUNDLE %s + +// BUNDLE: {{"*.clang.*"}} +// BUNDLE: {{"*.llvm-link"}} +// BUNDLE: {{".*opt"}} +// BUNDLE: {{".*llc"}} +// BUNDLE: {{".*lld"}} +// BUNDLE: {{".*clang-offload-bundler"}} + From cb23d9d5d75a8fac2a6c5162df6f4713b4dee9e2 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Thu, 3 Oct 2019 04:52:46 +0000 Subject: [PATCH 16/33] Fix driver tests when `LLVM_ENABLE_PER_TARGET_RUNTIME_DIR` is `ON` Some Driver tests relied on the default resource direcory having per-os per-arch subdirectory layout, and when clang is built with `-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON`, those test fail, because clang by default assumes per-target subdirectories. Explicitly set `-resource-dir` flag to point to a tree with per-os per-arch layout. See also: D45604, D62469 Differential Revision: https://reviews.llvm.org/D66981 Patch by Sergej Jaskiewicz . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373565 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Driver/arm-compiler-rt.c | 35 ++++++++++++++++---- test/Driver/print-libgcc-file-name-clangrt.c | 7 ++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/test/Driver/arm-compiler-rt.c b/test/Driver/arm-compiler-rt.c index a7e947c37867..b1acd6d67363 100644 --- a/test/Driver/arm-compiler-rt.c +++ b/test/Driver/arm-compiler-rt.c @@ -1,21 +1,42 @@ -// RUN: %clang -target arm-linux-gnueabi -rtlib=compiler-rt -### %s 2>&1 | FileCheck %s -check-prefix ARM-GNUEABI +// RUN: %clang -target arm-linux-gnueabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-GNUEABI // ARM-GNUEABI: "{{.*[/\\]}}libclang_rt.builtins-arm.a" -// RUN: %clang -target arm-linux-gnueabi -rtlib=compiler-rt -mfloat-abi=hard -### %s 2>&1 | FileCheck %s -check-prefix ARM-GNUEABI-ABI +// RUN: %clang -target arm-linux-gnueabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -mfloat-abi=hard -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-GNUEABI-ABI // ARM-GNUEABI-ABI: "{{.*[/\\]}}libclang_rt.builtins-armhf.a" -// RUN: %clang -target arm-linux-gnueabihf -rtlib=compiler-rt -### %s 2>&1 | FileCheck %s -check-prefix ARM-GNUEABIHF +// RUN: %clang -target arm-linux-gnueabihf \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-GNUEABIHF // ARM-GNUEABIHF: "{{.*[/\\]}}libclang_rt.builtins-armhf.a" -// RUN: %clang -target arm-linux-gnueabihf -rtlib=compiler-rt -mfloat-abi=soft -### %s 2>&1 | FileCheck %s -check-prefix ARM-GNUEABIHF-ABI +// RUN: %clang -target arm-linux-gnueabihf \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -mfloat-abi=soft -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-GNUEABIHF-ABI // ARM-GNUEABIHF-ABI: "{{.*[/\\]}}libclang_rt.builtins-arm.a" -// RUN: %clang -target arm-windows-itanium -rtlib=compiler-rt -### %s 2>&1 | FileCheck %s -check-prefix ARM-WINDOWS +// RUN: %clang -target arm-windows-itanium \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-WINDOWS // ARM-WINDOWS: "{{.*[/\\]}}clang_rt.builtins-arm.lib" -// RUN: %clang -target arm-linux-androideabi -rtlib=compiler-rt -### %s 2>&1 | FileCheck %s -check-prefix ARM-ANDROID +// RUN: %clang -target arm-linux-androideabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-ANDROID // ARM-ANDROID: "{{.*[/\\]}}libclang_rt.builtins-arm-android.a" -// RUN: %clang -target arm-linux-androideabi -rtlib=compiler-rt -mfloat-abi=hard -### %s 2>&1 | FileCheck %s -check-prefix ARM-ANDROIDHF +// RUN: %clang -target arm-linux-androideabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ +// RUN: -rtlib=compiler-rt -mfloat-abi=hard -### %s 2>&1 \ +// RUN: | FileCheck %s -check-prefix ARM-ANDROIDHF // ARM-ANDROIDHF: "{{.*[/\\]}}libclang_rt.builtins-armhf-android.a" diff --git a/test/Driver/print-libgcc-file-name-clangrt.c b/test/Driver/print-libgcc-file-name-clangrt.c index ce941dc4a128..74a88e565bb8 100644 --- a/test/Driver/print-libgcc-file-name-clangrt.c +++ b/test/Driver/print-libgcc-file-name-clangrt.c @@ -2,11 +2,13 @@ // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=x86_64-pc-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-X8664 %s // CHECK-CLANGRT-X8664: libclang_rt.builtins-x86_64.a // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=i386-pc-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-I386 %s // CHECK-CLANGRT-I386: libclang_rt.builtins-i386.a @@ -14,24 +16,29 @@ // // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=i686-pc-linux \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-I386 %s // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=arm-linux-gnueabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM %s // CHECK-CLANGRT-ARM: libclang_rt.builtins-arm.a // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=arm-linux-androideabi \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-ANDROID %s // CHECK-CLANGRT-ARM-ANDROID: libclang_rt.builtins-arm-android.a // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=arm-linux-gnueabihf \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARMHF %s // CHECK-CLANGRT-ARMHF: libclang_rt.builtins-armhf.a // RUN: %clang -rtlib=compiler-rt -print-libgcc-file-name 2>&1 \ // RUN: --target=arm-linux-gnueabi -mfloat-abi=hard \ +// RUN: -resource-dir=%S/Inputs/resource_dir_with_arch_subdir \ // RUN: | FileCheck --check-prefix=CHECK-CLANGRT-ARM-ABI %s // CHECK-CLANGRT-ARM-ABI: libclang_rt.builtins-armhf.a From 5fb4ff534428df6daec215a0487df1d382792cb4 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Thu, 3 Oct 2019 09:55:13 +0000 Subject: [PATCH 17/33] [clang][NFC] Fix misspellings in ExternalASTMerger.h git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373577 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExternalASTMerger.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h index d3942ee0a485..b718323b669d 100644 --- a/include/clang/AST/ExternalASTMerger.h +++ b/include/clang/AST/ExternalASTMerger.h @@ -23,7 +23,7 @@ namespace clang { /// ExternalASTSource implementation that merges information from several /// ASTContexts. /// -/// ExtermalASTMerger maintains a vector of ASTImporters that it uses to import +/// ExternalASTMerger maintains a vector of ASTImporters that it uses to import /// (potentially incomplete) Decls and DeclContexts from the source ASTContexts /// in response to ExternalASTSource API calls. /// @@ -37,7 +37,7 @@ namespace clang { /// lookup. In this case, Origins contains an entry overriding lookup and /// specifying the correct pair of DeclContext/ASTContext. /// -/// - The DeclContext of origin was determined by another ExterenalASTMerger. +/// - The DeclContext of origin was determined by another ExternalASTMerger. /// (This is possible when the source ASTContext for one of the Importers has /// its own ExternalASTMerger). The origin must be properly forwarded in this /// case. @@ -94,7 +94,7 @@ class ExternalASTMerger : public ExternalASTSource { }; private: - /// The target for this ExtenralASTMerger. + /// The target for this ExternalASTMerger. ImporterTarget Target; /// ExternalASTMerger has multiple ASTImporters that import into the same /// TU. This is the shared state for all ASTImporters of this @@ -158,7 +158,7 @@ class ExternalASTMerger : public ExternalASTSource { /// OriginContext. bool HasImporterForOrigin(ASTContext &OriginContext); - /// Returns a reference to the ASTRImporter from Importers whose origin + /// Returns a reference to the ASTImporter from Importers whose origin /// is OriginContext. This allows manual import of ASTs while preserving the /// OriginMap correctly. ASTImporter &ImporterForOrigin(ASTContext &OriginContext); From 84d475a5ed105e42257720e7720ec3f3faecfdda Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Thu, 3 Oct 2019 11:22:48 +0000 Subject: [PATCH 18/33] Silence static analyzer getAs null dereference warnings. NFCI. The static analyzer is warning about potential null dereferences, but in these cases we should be able to use castAs directly and if not assert will fire for us. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373584 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/APValue.cpp | 2 +- lib/AST/DeclCXX.cpp | 4 ++-- lib/AST/Expr.cpp | 6 +++--- lib/AST/ExprConstant.cpp | 2 +- lib/AST/InheritViz.cpp | 4 ++-- lib/AST/Interp/Program.cpp | 4 ++-- lib/AST/ItaniumMangle.cpp | 2 +- lib/AST/JSONNodeDumper.cpp | 2 +- lib/AST/TextNodeDumper.cpp | 4 ++-- lib/AST/VTTBuilder.cpp | 12 ++++++------ lib/CodeGen/CGCXX.cpp | 2 +- lib/CodeGen/CGCXXABI.cpp | 4 ++-- lib/CodeGen/CGCall.cpp | 4 ++-- lib/CodeGen/CGClass.cpp | 22 +++++++++++----------- lib/CodeGen/CGDebugInfo.cpp | 2 +- lib/CodeGen/CGDecl.cpp | 2 +- lib/CodeGen/CGExprCXX.cpp | 11 ++++------- lib/CodeGen/CGExprConstant.cpp | 4 ++-- lib/CodeGen/CGExprScalar.cpp | 4 ++-- lib/CodeGen/CodeGenTypes.cpp | 7 +++---- lib/CodeGen/TargetInfo.cpp | 8 ++++---- lib/Frontend/Rewrite/RewriteModernObjC.cpp | 16 ++++++++-------- lib/Frontend/Rewrite/RewriteObjC.cpp | 2 +- lib/Sema/SemaAccess.cpp | 4 ++-- lib/Sema/SemaChecking.cpp | 2 +- lib/Sema/SemaDecl.cpp | 4 ++-- lib/Sema/SemaDeclAttr.cpp | 2 +- lib/Sema/SemaDeclCXX.cpp | 11 ++++++----- lib/Sema/SemaExceptionSpec.cpp | 2 +- lib/Sema/SemaExprCXX.cpp | 4 ++-- lib/Sema/SemaExprMember.cpp | 2 +- lib/Sema/SemaLookup.cpp | 2 +- 32 files changed, 80 insertions(+), 83 deletions(-) diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index f29d6f5554c5..50f8d05dacb4 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -652,7 +652,7 @@ void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx, } case APValue::Struct: { Out << '{'; - const RecordDecl *RD = Ty->getAs()->getDecl(); + const RecordDecl *RD = Ty->castAs()->getDecl(); bool First = true; if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast(RD); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 95b14e494a3b..3602f1189e97 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -218,7 +218,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (BaseType->isDependentType()) continue; auto *BaseClassDecl = - cast(BaseType->getAs()->getDecl()); + cast(BaseType->castAs()->getDecl()); // C++2a [class]p7: // A standard-layout class is a class that: @@ -1909,7 +1909,7 @@ bool CXXRecordDecl::mayBeAbstract() const { for (const auto &B : bases()) { const auto *BaseDecl = - cast(B.getType()->getAs()->getDecl()); + cast(B.getType()->castAs()->getDecl()); if (BaseDecl->isAbstract()) return true; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index c9394bba2dd5..339f471a2c01 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -85,8 +85,8 @@ const Expr *Expr::skipRValueSubobjectAdjustments( CE->getCastKind() == CK_UncheckedDerivedToBase) && E->getType()->isRecordType()) { E = CE->getSubExpr(); - CXXRecordDecl *Derived - = cast(E->getType()->getAs()->getDecl()); + auto *Derived = + cast(E->getType()->castAs()->getDecl()); Adjustments.push_back(SubobjectAdjustment(CE, Derived)); continue; } @@ -3205,7 +3205,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; - RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + RecordDecl *RD = ILE->getType()->castAs()->getDecl(); for (const auto *Field : RD->fields()) { // If this is a union, skip all the fields that aren't being initialized. if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 908e80123404..a50a67dc211c 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -7211,7 +7211,7 @@ class LValueExprEvaluatorBase const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast(E->getMemberDecl())) { - assert(BaseTy->getAs()->getDecl()->getCanonicalDecl() == + assert(BaseTy->castAs()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index 4b3d5bee5631..2ed0ce1c79c5 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -90,8 +90,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { Out << " \"];\n"; // Display the base classes. - const CXXRecordDecl *Decl - = static_cast(Type->getAs()->getDecl()); + const auto *Decl = + static_cast(Type->castAs()->getDecl()); for (const auto &Base : Decl->bases()) { QualType CanonBaseType = Context.getCanonicalType(Base.getType()); diff --git a/lib/AST/Interp/Program.cpp b/lib/AST/Interp/Program.cpp index c8c6e3762246..d947b4746f8c 100644 --- a/lib/AST/Interp/Program.cpp +++ b/lib/AST/Interp/Program.cpp @@ -238,7 +238,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { if (Spec.isVirtual()) continue; - const RecordDecl *BD = Spec.getType()->getAs()->getDecl(); + const RecordDecl *BD = Spec.getType()->castAs()->getDecl(); Record *BR = getOrCreateRecord(BD); if (Descriptor *Desc = GetBaseDesc(BD, BR)) { Size += align(sizeof(InlineDescriptor)); @@ -250,7 +250,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) { } for (const CXXBaseSpecifier &Spec : CD->vbases()) { - const RecordDecl *BD = Spec.getType()->getAs()->getDecl(); + const RecordDecl *BD = Spec.getType()->castAs()->getDecl(); Record *BR = getOrCreateRecord(BD); if (Descriptor *Desc = GetBaseDesc(BD, BR)) { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 1c4ffac0981a..bea96dec9da9 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1324,7 +1324,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, if (const VarDecl *VD = dyn_cast(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = VD->getType()->getAs()->getDecl(); + const RecordDecl *RD = VD->getType()->castAs()->getDecl(); // Itanium C++ ABI 5.1.2: // diff --git a/lib/AST/JSONNodeDumper.cpp b/lib/AST/JSONNodeDumper.cpp index 049ce0d6ff24..2f76a1766727 100644 --- a/lib/AST/JSONNodeDumper.cpp +++ b/lib/AST/JSONNodeDumper.cpp @@ -286,7 +286,7 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) { for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) { const CXXBaseSpecifier *Base = *I; const auto *RD = - cast(Base->getType()->getAs()->getDecl()); + cast(Base->getType()->castAs()->getDecl()); llvm::json::Object Val{{"name", RD->getName()}}; if (Base->isVirtual()) diff --git a/lib/AST/TextNodeDumper.cpp b/lib/AST/TextNodeDumper.cpp index a540346ad459..9b76652277c9 100644 --- a/lib/AST/TextNodeDumper.cpp +++ b/lib/AST/TextNodeDumper.cpp @@ -636,8 +636,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) { if (!First) OS << " -> "; - const CXXRecordDecl *RD = - cast(Base->getType()->getAs()->getDecl()); + const auto *RD = + cast(Base->getType()->castAs()->getDecl()); if (Base->isVirtual()) OS << "virtual "; diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp index 53d0ef09f14c..d58e87517785 100644 --- a/lib/AST/VTTBuilder.cpp +++ b/lib/AST/VTTBuilder.cpp @@ -64,8 +64,8 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { if (I.isVirtual()) continue; - const CXXRecordDecl *BaseDecl = - cast(I.getType()->getAs()->getDecl()); + const auto *BaseDecl = + cast(I.getType()->castAs()->getDecl()); const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); CharUnits BaseOffset = Base.getBaseOffset() + @@ -90,8 +90,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, return; for (const auto &I : RD->bases()) { - const CXXRecordDecl *BaseDecl = - cast(I.getType()->getAs()->getDecl()); + const auto *BaseDecl = + cast(I.getType()->castAs()->getDecl()); // Itanium C++ ABI 2.6.2: // Secondary virtual pointers are present for all bases with either @@ -154,8 +154,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) { for (const auto &I : RD->bases()) { - const CXXRecordDecl *BaseDecl = - cast(I.getType()->getAs()->getDecl()); + const auto *BaseDecl = + cast(I.getType()->castAs()->getDecl()); // Check if this is a virtual base. if (I.isVirtual()) { diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 6d903a0d09e2..a39bf0f6de2f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -80,7 +80,7 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { // Skip base classes with trivial destructors. const auto *Base = - cast(I.getType()->getAs()->getDecl()); + cast(I.getType()->castAs()->getDecl()); if (Base->hasTrivialDestructor()) continue; // If we've already found a base class with a non-trivial diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index 041c0f8959fd..23dae2b61d04 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -46,8 +46,8 @@ CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer( ThisPtrForCall = This.getPointer(); const FunctionProtoType *FPT = MPT->getPointeeType()->getAs(); - const CXXRecordDecl *RD = - cast(MPT->getClass()->getAs()->getDecl()); + const auto *RD = + cast(MPT->getClass()->castAs()->getDecl()); llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType( CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr)); llvm::Constant *FnPtr = llvm::Constant::getNullValue(FTy->getPointerTo()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index fc514beab17d..449b8c49542f 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -3092,7 +3092,7 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, // Deactivate the cleanup for the callee-destructed param that was pushed. if (hasAggregateEvaluationKind(type) && !CurFuncIsThunk && - type->getAs()->getDecl()->isParamDestroyedInCallee() && + type->castAs()->getDecl()->isParamDestroyedInCallee() && param->needsDestruction(getContext())) { EHScopeStack::stable_iterator cleanup = CalleeDestructedParamCleanups.lookup(cast(param)); @@ -3577,7 +3577,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, // However, we still have to push an EH-only cleanup in case we unwind before // we make it to the call. if (HasAggregateEvalKind && - type->getAs()->getDecl()->isParamDestroyedInCallee()) { + type->castAs()->getDecl()->isParamDestroyedInCallee()) { // If we're using inalloca, use the argument memory. Otherwise, use a // temporary. AggValueSlot Slot; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 76ab88523971..f228329ad9b6 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -161,8 +161,8 @@ CharUnits CodeGenModule::computeNonVirtualBaseClassOffset( // Get the layout. const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *BaseDecl = - cast(Base->getType()->getAs()->getDecl()); + const auto *BaseDecl = + cast(Base->getType()->castAs()->getDecl()); // Add the offset. Offset += Layout.getBaseClassOffset(BaseDecl); @@ -279,8 +279,8 @@ Address CodeGenFunction::GetAddressOfBaseClass( // *start* with a step down to the correct virtual base subobject, // and hence will not require any further steps. if ((*Start)->isVirtual()) { - VBase = - cast((*Start)->getType()->getAs()->getDecl()); + VBase = cast( + (*Start)->getType()->castAs()->getDecl()); ++Start; } @@ -536,8 +536,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, Address ThisPtr = CGF.LoadCXXThisAddress(); const Type *BaseType = BaseInit->getBaseClass(); - CXXRecordDecl *BaseClassDecl = - cast(BaseType->getAs()->getDecl()); + const auto *BaseClassDecl = + cast(BaseType->castAs()->getDecl()); bool isBaseVirtual = BaseInit->isBaseVirtual(); @@ -1245,7 +1245,7 @@ namespace { static bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) { const Type *BaseType = BaseInit->getBaseClass(); const auto *BaseClassDecl = - cast(BaseType->getAs()->getDecl()); + cast(BaseType->castAs()->getDecl()); return BaseClassDecl->isDynamicClass(); } @@ -1814,8 +1814,8 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD, // We push them in the forward order so that they'll be popped in // the reverse order. for (const auto &Base : ClassDecl->vbases()) { - CXXRecordDecl *BaseClassDecl - = cast(Base.getType()->getAs()->getDecl()); + auto *BaseClassDecl = + cast(Base.getType()->castAs()->getDecl()); // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) @@ -2530,8 +2530,8 @@ void CodeGenFunction::getVTablePointers(BaseSubobject Base, // Traverse bases. for (const auto &I : RD->bases()) { - CXXRecordDecl *BaseDecl - = cast(I.getType()->getAs()->getDecl()); + auto *BaseDecl = + cast(I.getType()->castAs()->getDecl()); // Ignore classes without a vtable. if (!BaseDecl->isDynamicClass()) diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 71d99bc551c4..576d1b63310f 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -1699,7 +1699,7 @@ void CGDebugInfo::CollectCXXBasesAux( const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); for (const auto &BI : Bases) { const auto *Base = - cast(BI.getType()->getAs()->getDecl()); + cast(BI.getType()->castAs()->getDecl()); if (!SeenTypes.insert(Base).second) continue; auto *BaseTy = getOrCreateType(BI.getType(), Unit); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 5c0d52a16332..e40e96868a86 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -2395,7 +2395,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Don't push a cleanup in a thunk for a method that will also emit a // cleanup. if (hasAggregateEvaluationKind(Ty) && !CurFuncIsThunk && - Ty->getAs()->getDecl()->isParamDestroyedInCallee()) { + Ty->castAs()->getDecl()->isParamDestroyedInCallee()) { if (QualType::DestructionKind DtorKind = D.needsDestruction(getContext())) { assert((DtorKind == QualType::DK_cxx_destructor || diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 9057d1605943..d7b1d9ba9e79 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -418,13 +418,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, const Expr *BaseExpr = BO->getLHS(); const Expr *MemFnExpr = BO->getRHS(); - const MemberPointerType *MPT = - MemFnExpr->getType()->castAs(); - - const FunctionProtoType *FPT = - MPT->getPointeeType()->castAs(); - const CXXRecordDecl *RD = - cast(MPT->getClass()->getAs()->getDecl()); + const auto *MPT = MemFnExpr->getType()->castAs(); + const auto *FPT = MPT->getPointeeType()->castAs(); + const auto *RD = + cast(MPT->getClass()->castAs()->getDecl()); // Emit the 'this' pointer. Address This = Address::invalid(); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 31cf2aef1ba0..5e51f2e310fd 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -659,7 +659,7 @@ static bool EmitDesignatedInitUpdater(ConstantEmitter &Emitter, } bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) { - RecordDecl *RD = ILE->getType()->getAs()->getDecl(); + RecordDecl *RD = ILE->getType()->castAs()->getDecl(); const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); unsigned FieldNo = -1; @@ -839,7 +839,7 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, } llvm::Constant *ConstStructBuilder::Finalize(QualType Type) { - RecordDecl *RD = Type->getAs()->getDecl(); + RecordDecl *RD = Type->castAs()->getDecl(); llvm::Type *ValTy = CGM.getTypes().ConvertType(Type); return Builder.build(ValTy, RD->hasFlexibleArrayMember()); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 4676be40768f..bff88b2feca2 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -2662,7 +2662,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); - RecordDecl *RD = CurrentType->getAs()->getDecl(); + RecordDecl *RD = CurrentType->castAs()->getDecl(); const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); // Compute the index of the field in its parent. @@ -2695,7 +2695,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { continue; } - RecordDecl *RD = CurrentType->getAs()->getDecl(); + RecordDecl *RD = CurrentType->castAs()->getDecl(); const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); // Save the element type. diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index ec27d4b045e9..a458811d7a30 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -135,8 +135,8 @@ isSafeToConvert(const RecordDecl *RD, CodeGenTypes &CGT, // the class. if (const CXXRecordDecl *CRD = dyn_cast(RD)) { for (const auto &I : CRD->bases()) - if (!isSafeToConvert(I.getType()->getAs()->getDecl(), - CGT, AlreadyChecked)) + if (!isSafeToConvert(I.getType()->castAs()->getDecl(), CGT, + AlreadyChecked)) return false; } @@ -744,8 +744,7 @@ llvm::StructType *CodeGenTypes::ConvertRecordDeclType(const RecordDecl *RD) { if (const CXXRecordDecl *CRD = dyn_cast(RD)) { for (const auto &I : CRD->bases()) { if (I.isVirtual()) continue; - - ConvertRecordDeclType(I.getType()->getAs()->getDecl()); + ConvertRecordDeclType(I.getType()->castAs()->getDecl()); } } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index c4d0004f0e28..497f3f748128 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2809,8 +2809,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); - const CXXRecordDecl *Base = - cast(I.getType()->getAs()->getDecl()); + const auto *Base = + cast(I.getType()->castAs()->getDecl()); // Classify this field. // @@ -3071,8 +3071,8 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, for (const auto &I : CXXRD->bases()) { assert(!I.isVirtual() && !I.getType()->isDependentType() && "Unexpected base class!"); - const CXXRecordDecl *Base = - cast(I.getType()->getAs()->getDecl()); + const auto *Base = + cast(I.getType()->castAs()->getDecl()); // If the base is after the span we care about, ignore it. unsigned BaseOffset = Context.toBits(Layout.getBaseClassOffset(Base)); diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 563c7ca100ab..a11fed56fc34 100644 --- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -852,7 +852,7 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { IvarT = GetGroupRecordTypeForObjCIvarBitfield(D); if (!isa(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs()->getDecl(); + RecordDecl *RD = IvarT->castAs()->getDecl(); RD = RD->getDefinition(); if (RD && !RD->getDeclName().getAsIdentifierInfo()) { // decltype(((Foo_IMPL*)0)->bar) * @@ -3637,7 +3637,7 @@ bool RewriteModernObjC::RewriteObjCFieldDeclType(QualType &Type, return RewriteObjCFieldDeclType(ElemTy, Result); } else if (Type->isRecordType()) { - RecordDecl *RD = Type->getAs()->getDecl(); + RecordDecl *RD = Type->castAs()->getDecl(); if (RD->isCompleteDefinition()) { if (RD->isStruct()) Result += "\n\tstruct "; @@ -3727,15 +3727,15 @@ void RewriteModernObjC::RewriteLocallyDefinedNamedAggregates(FieldDecl *fieldDec return; if (Type->isArrayType()) Type = Context->getBaseElementType(Type); - ObjCContainerDecl *IDecl = - dyn_cast(fieldDecl->getDeclContext()); + + auto *IDecl = dyn_cast(fieldDecl->getDeclContext()); TagDecl *TD = nullptr; if (Type->isRecordType()) { - TD = Type->getAs()->getDecl(); + TD = Type->castAs()->getDecl(); } else if (Type->isEnumeralType()) { - TD = Type->getAs()->getDecl(); + TD = Type->castAs()->getDecl(); } if (TD) { @@ -5753,7 +5753,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { } } } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs()->getDecl(); + RecordDecl *RD = VD->getType()->castAs()->getDecl(); if (RD->isCompleteDefinition()) RewriteRecordBody(RD); } @@ -7494,7 +7494,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { IvarT = GetGroupRecordTypeForObjCIvarBitfield(D); if (!isa(IvarT) && IvarT->isRecordType()) { - RecordDecl *RD = IvarT->getAs()->getDecl(); + RecordDecl *RD = IvarT->castAs()->getDecl(); RD = RD->getDefinition(); if (RD && !RD->getDeclName().getAsIdentifierInfo()) { // decltype(((Foo_IMPL*)0)->bar) * diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp index e57a92683433..0fd0c7f50366 100644 --- a/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -4849,7 +4849,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } } } else if (VD->getType()->isRecordType()) { - RecordDecl *RD = VD->getType()->getAs()->getDecl(); + RecordDecl *RD = VD->getType()->castAs()->getDecl(); if (RD->isCompleteDefinition()) RewriteRecordBody(RD); } diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index b6fbbbff91f5..b20f279dcad2 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1834,8 +1834,8 @@ Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc, return AR_accessible; CXXRecordDecl *BaseD, *DerivedD; - BaseD = cast(Base->getAs()->getDecl()); - DerivedD = cast(Derived->getAs()->getDecl()); + BaseD = cast(Base->castAs()->getDecl()); + DerivedD = cast(Derived->castAs()->getDecl()); AccessTarget Entity(Context, AccessTarget::Base, BaseD, DerivedD, Path.Access); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f2ab27fedd40..38c502d6b3f3 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -14509,7 +14509,7 @@ void Sema::RefersToMemberWithReducedAlignment( QualType BaseType = ME->getBase()->getType(); if (ME->isArrow()) BaseType = BaseType->getPointeeType(); - RecordDecl *RD = BaseType->getAs()->getDecl(); + RecordDecl *RD = BaseType->castAs()->getDecl(); if (RD->isInvalidDecl()) return; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 7274fc96c5e8..9a0fb203533f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7767,7 +7767,7 @@ struct FindOverriddenMethod { /// CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { RecordDecl *BaseRecord = - Specifier->getType()->getAs()->getDecl(); + Specifier->getType()->castAs()->getDecl(); DeclarationName Name = Method->getDeclName(); @@ -16560,7 +16560,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); if (BaseType->isRecordType() && - BaseType->getAs()->getDecl()->hasObjectMember()) + BaseType->castAs()->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index d31b48c122f8..812819c50ea7 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -547,7 +547,7 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) { // If it's type-dependent, we assume it could have the attribute. if (Ty.isDependentType()) return true; - return Ty.getAs()->getDecl()->hasAttr(); + return Ty.castAs()->getDecl()->hasAttr(); }, BPaths, true)) return true; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index eaeca7806d4b..986339815965 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2479,7 +2479,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, } // If the base class is polymorphic or isn't empty, the new one is/isn't, too. - RecordDecl *BaseDecl = BaseType->getAs()->getDecl(); + RecordDecl *BaseDecl = BaseType->castAs()->getDecl(); assert(BaseDecl && "Record type has no declaration"); BaseDecl = BaseDecl->getDefinition(); assert(BaseDecl && "Base type is not incomplete, but has no definition"); @@ -8004,7 +8004,7 @@ struct FindHiddenVirtualMethod { /// to be used with CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { RecordDecl *BaseRecord = - Specifier->getType()->getAs()->getDecl(); + Specifier->getType()->castAs()->getDecl(); DeclarationName Name = Method->getDeclName(); assert(Name.getNameKind() == DeclarationName::Identifier); @@ -11845,7 +11845,8 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = - E->isRecordType() && E->getAs()->getDecl()->hasObjectMember(); + E->isRecordType() && + E->castAs()->getDecl()->hasObjectMember(); // Create a reference to the __builtin_objc_memmove_collectable function StringRef MemCpyName = NeedsCollectableMemCpy ? @@ -15535,8 +15536,8 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, return; for (const auto &I : RD->bases()) { - const CXXRecordDecl *Base = - cast(I.getType()->getAs()->getDecl()); + const auto *Base = + cast(I.getType()->castAs()->getDecl()); if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index fd843e4a0608..0f3a27233eef 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -154,7 +154,7 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { ReturnValueOnError = false; } if (!(PointeeT->isRecordType() && - PointeeT->getAs()->isBeingDefined()) && + PointeeT->castAs()->isBeingDefined()) && RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a9efbbc9e5e2..abd8745277a5 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2457,8 +2457,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AFS_Global) { - CXXRecordDecl *RD - = cast(AllocElemType->getAs()->getDecl()); + auto *RD = + cast(AllocElemType->castAs()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index e85499c0bbf0..87114a0fac63 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1006,7 +1006,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Rederive where we looked up. DeclContext *DC = (SS.isSet() ? computeDeclContext(SS, false) - : BaseType->getAs()->getDecl()); + : BaseType->castAs()->getDecl()); if (ExtraArgs) { ExprResult RetryExpr; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index fdb8f488471f..a098450f5cda 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2130,7 +2130,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, /// Callback that looks for any member of a class with the given name. static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, DeclarationName Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs()->getDecl(); + RecordDecl *BaseRecord = Specifier->getType()->castAs()->getDecl(); Path.Decls = BaseRecord->lookup(Name); return !Path.Decls.empty(); From 4eef7a8ad0695039c9eca1e5fe6c89a37ba8bdf2 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Thu, 3 Oct 2019 13:00:29 +0000 Subject: [PATCH 19/33] [Alignment][Clang][NFC] Add CharUnits::getAsAlign Summary: This is a prerequisite to removing `llvm::GlobalObject::setAlignment(unsigned)`. This is patch is part of a series to introduce an Alignment type. See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html See this patch for the introduction of the type: https://reviews.llvm.org/D64790 Reviewers: courbet Subscribers: jholewinski, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D68274 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373592 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/CharUnits.h | 5 +++ lib/CodeGen/CGCUDANV.cpp | 6 +-- lib/CodeGen/CGCall.cpp | 2 +- lib/CodeGen/CGCleanup.cpp | 4 +- lib/CodeGen/CGDecl.cpp | 8 ++-- lib/CodeGen/CGExpr.cpp | 6 +-- lib/CodeGen/CGExprAgg.cpp | 2 +- lib/CodeGen/CGExprCXX.cpp | 2 +- lib/CodeGen/CGExprConstant.cpp | 2 +- lib/CodeGen/CGObjCGNU.cpp | 8 ++-- lib/CodeGen/CGObjCMac.cpp | 37 ++++++++++--------- lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp | 6 +-- lib/CodeGen/CodeGenFunction.cpp | 2 +- lib/CodeGen/CodeGenFunction.h | 2 +- lib/CodeGen/CodeGenModule.cpp | 25 ++++++------- lib/CodeGen/ConstantInitBuilder.cpp | 2 +- lib/CodeGen/CoverageMappingGen.cpp | 2 +- lib/CodeGen/ItaniumCXXABI.cpp | 6 +-- lib/CodeGen/MicrosoftCXXABI.cpp | 4 +- .../ObjectFilePCHContainerOperations.cpp | 2 +- 20 files changed, 69 insertions(+), 64 deletions(-) diff --git a/include/clang/AST/CharUnits.h b/include/clang/AST/CharUnits.h index 37f489c7708a..f14d3abf71e5 100644 --- a/include/clang/AST/CharUnits.h +++ b/include/clang/AST/CharUnits.h @@ -14,6 +14,7 @@ #define LLVM_CLANG_AST_CHARUNITS_H #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/Alignment.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/MathExtras.h" @@ -177,6 +178,10 @@ namespace clang { /// getQuantity - Get the raw integer representation of this quantity. QuantityType getQuantity() const { return Quantity; } + /// getAsAlign - Returns Quantity as a valid llvm::Align, + /// Beware llvm::Align assumes power of two 8-bit bytes. + llvm::Align getAsAlign() const { return llvm::Align(Quantity); } + /// alignTo - Returns the next integer (mod 2**64) that is /// greater than or equal to this quantity and is a multiple of \p Align. /// Align must be non-zero. diff --git a/lib/CodeGen/CGCUDANV.cpp b/lib/CodeGen/CGCUDANV.cpp index 05aeef4194d4..5c5cbaff0252 100644 --- a/lib/CodeGen/CGCUDANV.cpp +++ b/lib/CodeGen/CGCUDANV.cpp @@ -93,7 +93,7 @@ class CGNVCUDARuntime : public CGCUDARuntime { GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::None); } if (Alignment) - GV->setAlignment(Alignment); + GV->setAlignment(llvm::Align(Alignment)); return llvm::ConstantExpr::getGetElementPtr(ConstStr.getElementType(), ConstStr.getPointer(), Zeros); @@ -628,7 +628,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { Linkage, /*Initializer=*/llvm::ConstantPointerNull::get(VoidPtrPtrTy), "__hip_gpubin_handle"); - GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity()); + GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign()); // Prevent the weak symbol in different shared libraries being merged. if (Linkage != llvm::GlobalValue::InternalLinkage) GpuBinaryHandle->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -669,7 +669,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { GpuBinaryHandle = new llvm::GlobalVariable( TheModule, VoidPtrPtrTy, false, llvm::GlobalValue::InternalLinkage, llvm::ConstantPointerNull::get(VoidPtrPtrTy), "__cuda_gpubin_handle"); - GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getQuantity()); + GpuBinaryHandle->setAlignment(CGM.getPointerAlign().getAsAlign()); CtorBuilder.CreateAlignedStore(RegisterFatbinCall, GpuBinaryHandle, CGM.getPointerAlign()); diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 449b8c49542f..e851d7bafd76 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -3841,7 +3841,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, AI = CreateTempAlloca(ArgStruct, "argmem"); } auto Align = CallInfo.getArgStructAlignment(); - AI->setAlignment(llvm::MaybeAlign(Align.getQuantity())); + AI->setAlignment(Align.getAsAlign()); AI->setUsedWithInAlloca(true); assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca()); ArgMemory = Address(AI, Align); diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index 1280bdb1932e..c117dd5c25c1 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -304,13 +304,13 @@ void EHScopeStack::Cleanup::anchor() {} static void createStoreInstBefore(llvm::Value *value, Address addr, llvm::Instruction *beforeInst) { auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst); - store->setAlignment(addr.getAlignment().getQuantity()); + store->setAlignment(addr.getAlignment().getAsAlign()); } static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name, llvm::Instruction *beforeInst) { auto load = new llvm::LoadInst(addr.getPointer(), name, beforeInst); - load->setAlignment(llvm::MaybeAlign(addr.getAlignment().getQuantity())); + load->setAlignment(addr.getAlignment().getAsAlign()); return load; } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index e40e96868a86..46ea9c32eeed 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -250,7 +250,7 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( llvm::GlobalVariable *GV = new llvm::GlobalVariable( getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name, nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); - GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + GV->setAlignment(getContext().getDeclAlign(&D).getAsAlign()); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); @@ -408,7 +408,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, if (D.getInit() && !isCudaSharedVar) var = AddInitializerToStaticVarDecl(D, var); - var->setAlignment(alignment.getQuantity()); + var->setAlignment(alignment.getAsAlign()); if (D.hasAttr()) CGM.AddGlobalAnnotations(&D, var); @@ -1112,11 +1112,11 @@ Address CodeGenModule::createUnnamedGlobalFrom(const VarDecl &D, llvm::GlobalVariable *GV = new llvm::GlobalVariable( getModule(), Ty, isConstant, llvm::GlobalValue::PrivateLinkage, Constant, Name, InsertBefore, llvm::GlobalValue::NotThreadLocal, AS); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); CacheEntry = GV; } else if (CacheEntry->getAlignment() < Align.getQuantity()) { - CacheEntry->setAlignment(Align.getQuantity()); + CacheEntry->setAlignment(Align.getAsAlign()); } return Address(CacheEntry, Align); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 36015c21915c..776d21f4ea96 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -66,7 +66,7 @@ Address CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty, const Twine &Name, llvm::Value *ArraySize) { auto Alloca = CreateTempAlloca(Ty, Name, ArraySize); - Alloca->setAlignment(llvm::MaybeAlign(Align.getQuantity())); + Alloca->setAlignment(Align.getAsAlign()); return Address(Alloca, Align); } @@ -126,7 +126,7 @@ Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, void CodeGenFunction::InitTempAlloca(Address Var, llvm::Value *Init) { assert(isa(Var.getPointer())); auto *Store = new llvm::StoreInst(Init, Var.getPointer()); - Store->setAlignment(Var.getAlignment().getQuantity()); + Store->setAlignment(Var.getAlignment().getAsAlign()); llvm::BasicBlock *Block = AllocaInsertPt->getParent(); Block->getInstList().insertAfter(AllocaInsertPt->getIterator(), Store); } @@ -392,7 +392,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, llvm::GlobalValue::NotThreadLocal, CGF.getContext().getTargetAddressSpace(AS)); CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty); - GV->setAlignment(alignment.getQuantity()); + GV->setAlignment(alignment.getAsAlign()); llvm::Constant *C = GV; if (AS != LangAS::Default) C = TCG.performAddrSpaceCast( diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 9610a04be343..ab51512ef98c 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -501,7 +501,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, CGM.getContext().getTargetAddressSpace(AS)); Emitter.finalize(GV); CharUnits Align = CGM.getContext().getTypeAlignInChars(ArrayQTy); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); EmitFinalDestCopy(ArrayQTy, CGF.MakeAddrLValue(GV, ArrayQTy, Align)); return; } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index d7b1d9ba9e79..49527e9691a7 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -532,7 +532,7 @@ static void EmitNullBaseClassInitialization(CodeGenFunction &CGF, CharUnits Align = std::max(Layout.getNonVirtualAlignment(), DestPtr.getAlignment()); - NullVariable->setAlignment(Align.getQuantity()); + NullVariable->setAlignment(Align.getAsAlign()); Address SrcPtr = Address(CGF.EmitCastToVoidPtr(NullVariable), Align); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 5e51f2e310fd..03ef4ab18422 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -907,7 +907,7 @@ static ConstantAddress tryEmitGlobalCompoundLiteral(CodeGenModule &CGM, llvm::GlobalVariable::NotThreadLocal, CGM.getContext().getTargetAddressSpace(addressSpace)); emitter.finalize(GV); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); CGM.setAddrOfConstantCompoundLiteral(E, GV); return ConstantAddress(GV, Align); } diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index ee0fd184c64d..c21f257442c9 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -1294,7 +1294,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { // Emit a placeholder symbol. GV = new llvm::GlobalVariable(TheModule, ProtocolTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, Name); - GV->setAlignment(CGM.getPointerAlign().getQuantity()); + GV->setAlignment(CGM.getPointerAlign().getAsAlign()); } return llvm::ConstantExpr::getBitCast(GV, ProtocolPtrTy); } @@ -1318,7 +1318,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName); GV->setComdat(TheModule.getOrInsertComdat(RefName)); GV->setSection(sectionName()); - GV->setAlignment(CGM.getPointerAlign().getQuantity()); + GV->setAlignment(CGM.getPointerAlign().getAsAlign()); Ref = GV; } EmittedProtocolRef = true; @@ -1497,7 +1497,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { Sym->setSection((Section + SecSuffix).str()); Sym->setComdat(TheModule.getOrInsertComdat((Prefix + Section).str())); - Sym->setAlignment(CGM.getPointerAlign().getQuantity()); + Sym->setAlignment(CGM.getPointerAlign().getAsAlign()); return Sym; }; return { Sym("__start_", "$a"), Sym("__stop", "$z") }; @@ -4087,7 +4087,7 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, auto GV = new llvm::GlobalVariable(TheModule, IntTy, false, llvm::GlobalValue::LinkOnceAnyLinkage, llvm::Constant::getNullValue(IntTy), name); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); Offset = GV; } Offset = CGF.Builder.CreateAlignedLoad(Offset, Align); diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2b92c4b9e6df..8e28b2f05c16 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -2018,7 +2018,7 @@ CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) { GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); // Don't enforce the target's minimum global alignment, since the only use // of the string is via this class initializer. - GV->setAlignment(1); + GV->setAlignment(llvm::Align::None()); Fields.addBitCast(GV, CGM.Int8PtrTy); // String length. @@ -3101,7 +3101,7 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { nullptr, "OBJC_PROTOCOL_" + PD->getName()); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); // FIXME: Is this necessary? Why only for protocol? - Entry->setAlignment(4); + Entry->setAlignment(llvm::Align(4)); } return Entry; @@ -3607,7 +3607,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { "Forward metaclass reference has incorrect type."); values.finishAndSetAsInitializer(GV); GV->setSection(Section); - GV->setAlignment(CGM.getPointerAlign().getQuantity()); + GV->setAlignment(CGM.getPointerAlign().getAsAlign()); CGM.addCompilerUsedGlobal(GV); } else GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true); @@ -4014,7 +4014,7 @@ llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name, new llvm::GlobalVariable(CGM.getModule(), Ty, false, LT, Init, Name); if (!Section.empty()) GV->setSection(Section); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); if (AddToUsed) CGM.addCompilerUsedGlobal(GV); return GV; @@ -4062,7 +4062,7 @@ CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type, if (CGM.getTriple().isOSBinFormatMachO()) GV->setSection(Section); GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - GV->setAlignment(CharUnits::One().getQuantity()); + GV->setAlignment(CharUnits::One().getAsAlign()); CGM.addCompilerUsedGlobal(GV); return GV; @@ -6074,7 +6074,8 @@ void CGObjCNonFragileABIMac::AddModuleClassList( llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, LT, Init, SymbolName); - GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType())); + GV->setAlignment( + llvm::Align(CGM.getDataLayout().getABITypeAlignment(Init->getType()))); GV->setSection(SectionName); CGM.addCompilerUsedGlobal(GV); } @@ -6317,8 +6318,8 @@ CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI, if (CGM.getTriple().isOSBinFormatMachO()) GV->setSection("__DATA, __objc_data"); - GV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)); + GV->setAlignment(llvm::Align( + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy))); if (!CGM.getTriple().isOSBinFormatCOFF()) if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -6525,7 +6526,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF, PTGV->setSection(GetSectionName("__objc_protorefs", "coalesced,no_dead_strip")); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); - PTGV->setAlignment(Align.getQuantity()); + PTGV->setAlignment(Align.getAsAlign()); if (!CGM.getTriple().isOSBinFormatMachO()) PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolName)); CGM.addUsedGlobal(PTGV); @@ -6757,8 +6758,8 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, llvm::GlobalVariable *IvarOffsetGV = ObjCIvarOffsetVariable(ID, Ivar); IvarOffsetGV->setInitializer( llvm::ConstantInt::get(ObjCTypes.IvarOffsetVarTy, Offset)); - IvarOffsetGV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy)); + IvarOffsetGV->setAlignment(llvm::Align( + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.IvarOffsetVarTy))); if (!CGM.getTriple().isOSBinFormatCOFF()) { // FIXME: This matches gcc, but shouldn't the visibility be set on the use @@ -6984,8 +6985,8 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( ProtocolRef); if (!CGM.getTriple().isOSBinFormatMachO()) PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef)); - PTGV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); + PTGV->setAlignment(llvm::Align( + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy))); PTGV->setSection(GetSectionName("__objc_protolist", "coalesced,no_dead_strip")); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -7336,7 +7337,7 @@ CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF, CGM.getModule(), ClassGV->getType(), false, getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV, "OBJC_CLASSLIST_REFERENCES_$_"); - Entry->setAlignment(CGF.getPointerAlign().getQuantity()); + Entry->setAlignment(CGF.getPointerAlign().getAsAlign()); if (!ID || !ID->hasAttr()) Entry->setSection(SectionName); @@ -7375,7 +7376,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF, CGM.getModule(), ClassGV->getType(), false, getLinkageTypeForObjCMetadata(CGM, SectionName), ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_"); - Entry->setAlignment(CGF.getPointerAlign().getQuantity()); + Entry->setAlignment(CGF.getPointerAlign().getAsAlign()); Entry->setSection(SectionName); CGM.addCompilerUsedGlobal(Entry); } @@ -7399,7 +7400,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF, CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false, getLinkageTypeForObjCMetadata(CGM, SectionName), MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_"); - Entry->setAlignment(Align.getQuantity()); + Entry->setAlignment(Align.getAsAlign()); Entry->setSection(SectionName); CGM.addCompilerUsedGlobal(Entry); } @@ -7498,7 +7499,7 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF, "OBJC_SELECTOR_REFERENCES_"); Entry->setExternallyInitialized(true); Entry->setSection(SectionName); - Entry->setAlignment(Align.getQuantity()); + Entry->setAlignment(Align.getAsAlign()); CGM.addCompilerUsedGlobal(Entry); } @@ -7731,7 +7732,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, : llvm::GlobalValue::WeakAnyLinkage; if (Entry) { values.finishAndSetAsInitializer(Entry); - Entry->setAlignment(CGM.getPointerAlign().getQuantity()); + Entry->setAlignment(CGM.getPointerAlign().getAsAlign()); } else { Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName, CGM.getPointerAlign(), diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index c6c595dcc2c6..746852485bab 100644 --- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -4730,7 +4730,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF, /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, CGM.getContext().getTargetAddressSpace(LangAS::cuda_constant)); CharUnits Align = CGM.getContext().getDeclAlign(VD); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); return Address(GV, Align); } case OMPAllocateDeclAttr::OMPPTeamMemAlloc: { @@ -4742,7 +4742,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF, /*InsertBefore=*/nullptr, llvm::GlobalValue::NotThreadLocal, CGM.getContext().getTargetAddressSpace(LangAS::cuda_shared)); CharUnits Align = CGM.getContext().getDeclAlign(VD); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); return Address(GV, Align); } case OMPAllocateDeclAttr::OMPLargeCapMemAlloc: @@ -4753,7 +4753,7 @@ Address CGOpenMPRuntimeNVPTX::getAddressOfLocalVariable(CodeGenFunction &CGF, llvm::GlobalValue::InternalLinkage, llvm::Constant::getNullValue(VarTy), VD->getName()); CharUnits Align = CGM.getContext().getDeclAlign(VD); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); return Address(GV, Align); } } diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index b2522cbc8ae8..e934ab34a3a2 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -1671,7 +1671,7 @@ CodeGenFunction::EmitNullInitialization(Address DestPtr, QualType Ty) { llvm::GlobalVariable::PrivateLinkage, NullConstant, Twine()); CharUnits NullAlign = DestPtr.getAlignment(); - NullVariable->setAlignment(NullAlign.getQuantity()); + NullVariable->setAlignment(NullAlign.getAsAlign()); Address SrcPtr(Builder.CreateBitCast(NullVariable, Builder.getInt8PtrTy()), NullAlign); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index c3060d1fb351..02007ab28abb 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1034,7 +1034,7 @@ class CodeGenFunction : public CodeGenTypeCache { assert(isInConditionalBranch()); llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back()); - store->setAlignment(addr.getAlignment().getQuantity()); + store->setAlignment(addr.getAlignment().getAsAlign()); } /// An RAII object to record that we're evaluating a statement diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5d1a3d556d20..6370561b83a0 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1182,7 +1182,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { // The LTO linker doesn't seem to like it when we set an alignment // on appending variables. Take it off as a workaround. - list->setAlignment(0); + list->setAlignment(llvm::None); Fns.clear(); } @@ -1596,11 +1596,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); if (alignment) - F->setAlignment(alignment); + F->setAlignment(llvm::Align(alignment)); if (!D->hasAttr()) if (LangOpts.FunctionAlignment) - F->setAlignment(1 << LangOpts.FunctionAlignment); + F->setAlignment(llvm::Align(1 << LangOpts.FunctionAlignment)); // Some C++ ABIs require 2-byte alignment for member functions, in order to // reserve a bit for differentiating between virtual and non-virtual member @@ -1608,7 +1608,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, // member function, set its alignment accordingly. if (getTarget().getCXXABI().areMemberFunctionsAligned()) { if (F->getAlignment() < 2 && isa(D)) - F->setAlignment(2); + F->setAlignment(llvm::Align(2)); } // In the cross-dso CFI mode with canonical jump tables, we want !type @@ -3448,7 +3448,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, // handling. GV->setConstant(isTypeConstant(D->getType(), false)); - GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); + GV->setAlignment(getContext().getDeclAlign(D).getAsAlign()); setLinkageForGV(GV, D); @@ -3598,7 +3598,7 @@ llvm::GlobalVariable *CodeGenModule::CreateOrReplaceCXXRuntimeVariable( !GV->hasAvailableExternallyLinkage()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); - GV->setAlignment(Alignment); + GV->setAlignment(llvm::MaybeAlign(Alignment)); return GV; } @@ -3994,8 +3994,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, GV->setConstant(true); } - GV->setAlignment(getContext().getDeclAlign(D).getQuantity()); - + GV->setAlignment(getContext().getDeclAlign(D).getAsAlign()); // On Darwin, if the normal linkage of a C++ thread_local variable is // LinkOnce or Weak, we keep the normal linkage to prevent multiple @@ -4694,7 +4693,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { // of the string is via this class initializer. CharUnits Align = isUTF16 ? Context.getTypeAlignInChars(Context.ShortTy) : Context.getTypeAlignInChars(Context.CharTy); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); // FIXME: We set the section explicitly to avoid a bug in ld64 224.1. // Without it LLVM can merge the string with a non unnamed_addr one during @@ -4847,7 +4846,7 @@ GenerateStringLiteral(llvm::Constant *C, llvm::GlobalValue::LinkageTypes LT, auto *GV = new llvm::GlobalVariable( M, C->getType(), !CGM.getLangOpts().WritableStrings, LT, C, GlobalName, nullptr, llvm::GlobalVariable::NotThreadLocal, AddrSpace); - GV->setAlignment(Alignment.getQuantity()); + GV->setAlignment(Alignment.getAsAlign()); GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); if (GV->isWeakForLinker()) { assert(CGM.supportsCOMDAT() && "Only COFF uses weak string literals"); @@ -4871,7 +4870,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S, Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { if (Alignment.getQuantity() > GV->getAlignment()) - GV->setAlignment(Alignment.getQuantity()); + GV->setAlignment(Alignment.getAsAlign()); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), Alignment); } @@ -4934,7 +4933,7 @@ ConstantAddress CodeGenModule::GetAddrOfConstantCString( Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { if (Alignment.getQuantity() > GV->getAlignment()) - GV->setAlignment(Alignment.getQuantity()); + GV->setAlignment(Alignment.getAsAlign()); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), Alignment); } @@ -5037,7 +5036,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); if (emitter) emitter->finalize(GV); setGVProperties(GV, VD); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); if (VD->getTLSKind()) diff --git a/lib/CodeGen/ConstantInitBuilder.cpp b/lib/CodeGen/ConstantInitBuilder.cpp index 40b1607b5626..2d63d88020be 100644 --- a/lib/CodeGen/ConstantInitBuilder.cpp +++ b/lib/CodeGen/ConstantInitBuilder.cpp @@ -79,7 +79,7 @@ ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer, /*insert before*/ nullptr, llvm::GlobalValue::NotThreadLocal, addressSpace); - GV->setAlignment(alignment.getQuantity()); + GV->setAlignment(alignment.getAsAlign()); resolveSelfReferences(GV); return GV; } diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp index 6d18027f16a8..0a7a4fe33ac2 100644 --- a/lib/CodeGen/CoverageMappingGen.cpp +++ b/lib/CodeGen/CoverageMappingGen.cpp @@ -1442,7 +1442,7 @@ void CoverageMappingModuleGen::emit() { CovDataVal, llvm::getCoverageMappingVarName()); CovData->setSection(getCoverageSection(CGM)); - CovData->setAlignment(8); + CovData->setAlignment(llvm::Align(8)); // Make sure the data doesn't get deleted. CGM.addUsedGlobal(CovData); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index d6e51c60cc7f..2945dec0bd7d 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2194,7 +2194,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, guard->setVisibility(var->getVisibility()); // If the variable is thread-local, so is its guard variable. guard->setThreadLocalMode(var->getThreadLocalMode()); - guard->setAlignment(guardAlignment.getQuantity()); + guard->setAlignment(guardAlignment.getAsAlign()); // The ABI says: "It is suggested that it be emitted in the same COMDAT // group as the associated data object." In practice, this doesn't work for @@ -2547,7 +2547,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( Guard->setThreadLocal(true); CharUnits GuardAlign = CharUnits::One(); - Guard->setAlignment(GuardAlign.getQuantity()); + Guard->setAlignment(GuardAlign.getAsAlign()); CodeGenFunction(CGM).GenerateCXXGlobalInitFunc( InitFunc, OrderedInits, ConstantAddress(Guard, GuardAlign)); @@ -3479,7 +3479,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( CharUnits Align = CGM.getContext().toCharUnitsFromBits(CGM.getTarget().getPointerAlign(0)); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); // The Itanium ABI specifies that type_info objects must be globally // unique, with one exception: if the type is an incomplete class diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index d1cd1b59fcd6..8a5ea844c21f 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -2355,7 +2355,7 @@ static ConstantAddress getInitThreadEpochPtr(CodeGenModule &CGM) { /*isConstant=*/false, llvm::GlobalVariable::ExternalLinkage, /*Initializer=*/nullptr, VarName, /*InsertBefore=*/nullptr, llvm::GlobalVariable::GeneralDynamicTLSModel); - GV->setAlignment(Align.getQuantity()); + GV->setAlignment(Align.getAsAlign()); return ConstantAddress(GV, Align); } @@ -2498,7 +2498,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, GV->getLinkage(), Zero, GuardName.str()); GuardVar->setVisibility(GV->getVisibility()); GuardVar->setDLLStorageClass(GV->getDLLStorageClass()); - GuardVar->setAlignment(GuardAlign.getQuantity()); + GuardVar->setAlignment(GuardAlign.getAsAlign()); if (GuardVar->isWeakForLinker()) GuardVar->setComdat( CGM.getModule().getOrInsertComdat(GuardVar->getName())); diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp index 84912954f72c..284e8022a3c4 100644 --- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -279,7 +279,7 @@ class PCHContainerGenerator : public ASTConsumer { *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data, "__clang_ast"); // The on-disk hashtable needs to be aligned. - ASTSym->setAlignment(8); + ASTSym->setAlignment(llvm::Align(8)); // Mach-O also needs a segment name. if (Triple.isOSBinFormatMachO()) From a782b2b93cd493f514a5ed77721b7a361bc91553 Mon Sep 17 00:00:00 2001 From: Yitzhak Mandelbaum Date: Thu, 3 Oct 2019 13:01:00 +0000 Subject: [PATCH 20/33] [libTooling] Add various Stencil combinators for expressions. Summary: This revision adds three new Stencil combinators: * `expression`, which idiomatically constructs the source for an expression, including wrapping the expression's source in parentheses if needed. * `deref`, which constructs an idiomatic dereferencing expression. * `addressOf`, which constructs an idiomatic address-taking expression. Reviewers: gribozavr Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D68315 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373593 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Tooling/Refactoring/Stencil.h | 17 +++++- lib/Tooling/Refactoring/Stencil.cpp | 63 +++++++++++++++++++- unittests/Tooling/StencilTest.cpp | 66 ++++++++++++++++++++- 3 files changed, 143 insertions(+), 3 deletions(-) diff --git a/include/clang/Tooling/Refactoring/Stencil.h b/include/clang/Tooling/Refactoring/Stencil.h index 3bd66e578b85..96fd978e945a 100644 --- a/include/clang/Tooling/Refactoring/Stencil.h +++ b/include/clang/Tooling/Refactoring/Stencil.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// /// -/// /file +/// \file /// This file defines the *Stencil* abstraction: a code-generating object, /// parameterized by named references to (bound) AST nodes. Given a match /// result, a stencil can be evaluated to a string of source code. @@ -154,6 +154,21 @@ inline StencilPart node(llvm::StringRef Id) { return selection(tooling::node(Id)); } +/// Generates the source of the expression bound to \p Id, wrapping it in +/// parentheses if it may parse differently depending on context. For example, a +/// binary operation is always wrapped, while a variable reference is never +/// wrapped. +StencilPart expression(llvm::StringRef Id); + +/// Constructs an idiomatic dereferencing of the expression bound to \p ExprId. +/// \p ExprId is wrapped in parentheses, if needed. +StencilPart deref(llvm::StringRef ExprId); + +/// Constructs an expression that idiomatically takes the address of the +/// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if +/// needed. +StencilPart addressOf(llvm::StringRef ExprId); + /// Constructs a `MemberExpr` that accesses the named member (\p Member) of the /// object bound to \p BaseId. The access is constructed idiomatically: if \p /// BaseId is bound to `e` and \p Member identifies member `m`, then returns diff --git a/lib/Tooling/Refactoring/Stencil.cpp b/lib/Tooling/Refactoring/Stencil.cpp index a01b81023389..f7687f91e494 100644 --- a/lib/Tooling/Refactoring/Stencil.cpp +++ b/lib/Tooling/Refactoring/Stencil.cpp @@ -24,6 +24,7 @@ using namespace clang; using namespace tooling; using ast_matchers::MatchFinder; +using ast_type_traits::DynTypedNode; using llvm::errc; using llvm::Error; using llvm::Expected; @@ -37,7 +38,7 @@ template const D *down_cast(const StencilPartInterface *P) { return static_cast(P); } -static llvm::Expected +static llvm::Expected getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) { auto &NodesMap = Nodes.getMap(); auto It = NodesMap.find(Id); @@ -60,6 +61,21 @@ struct DebugPrintNodeData { std::string Id; }; +// Operators that take a single node Id as an argument. +enum class UnaryNodeOperator { + Parens, + Deref, + Address, +}; + +// Generic container for stencil operations with a (single) node-id argument. +struct UnaryOperationData { + UnaryOperationData(UnaryNodeOperator Op, std::string Id) + : Op(Op), Id(std::move(Id)) {} + UnaryNodeOperator Op; + std::string Id; +}; + // The fragment of code corresponding to the selected range. struct SelectorData { explicit SelectorData(RangeSelector S) : Selector(std::move(S)) {} @@ -91,6 +107,10 @@ bool isEqualData(const DebugPrintNodeData &A, const DebugPrintNodeData &B) { return A.Id == B.Id; } +bool isEqualData(const UnaryOperationData &A, const UnaryOperationData &B) { + return A.Op == B.Op && A.Id == B.Id; +} + // Equality is not (yet) defined for \c RangeSelector. bool isEqualData(const SelectorData &, const SelectorData &) { return false; } @@ -130,6 +150,32 @@ Error evalData(const DebugPrintNodeData &Data, return Error::success(); } +Error evalData(const UnaryOperationData &Data, + const MatchFinder::MatchResult &Match, std::string *Result) { + const auto *E = Match.Nodes.getNodeAs(Data.Id); + if (E == nullptr) + return llvm::make_error( + errc::invalid_argument, "Id not bound or not Expr: " + Data.Id); + llvm::Optional Source; + switch (Data.Op) { + case UnaryNodeOperator::Parens: + Source = buildParens(*E, *Match.Context); + break; + case UnaryNodeOperator::Deref: + Source = buildDereference(*E, *Match.Context); + break; + case UnaryNodeOperator::Address: + Source = buildAddressOf(*E, *Match.Context); + break; + } + if (!Source) + return llvm::make_error( + errc::invalid_argument, + "Could not construct expression source from ID: " + Data.Id); + *Result += *Source; + return Error::success(); +} + Error evalData(const SelectorData &Data, const MatchFinder::MatchResult &Match, std::string *Result) { auto Range = Data.Selector(Match); @@ -239,6 +285,21 @@ StencilPart stencil::dPrint(StringRef Id) { return StencilPart(std::make_shared>(Id)); } +StencilPart stencil::expression(llvm::StringRef Id) { + return StencilPart(std::make_shared>( + UnaryNodeOperator::Parens, Id)); +} + +StencilPart stencil::deref(llvm::StringRef ExprId) { + return StencilPart(std::make_shared>( + UnaryNodeOperator::Deref, ExprId)); +} + +StencilPart stencil::addressOf(llvm::StringRef ExprId) { + return StencilPart(std::make_shared>( + UnaryNodeOperator::Address, ExprId)); +} + StencilPart stencil::access(StringRef BaseId, StencilPart Member) { return StencilPart( std::make_shared>(BaseId, std::move(Member))); diff --git a/unittests/Tooling/StencilTest.cpp b/unittests/Tooling/StencilTest.cpp index 2202693f023d..f441fae80322 100644 --- a/unittests/Tooling/StencilTest.cpp +++ b/unittests/Tooling/StencilTest.cpp @@ -20,14 +20,19 @@ using namespace tooling; using namespace ast_matchers; namespace { +using ::llvm::Failed; using ::llvm::HasValue; +using ::llvm::StringError; using ::testing::AllOf; using ::testing::Eq; using ::testing::HasSubstr; using MatchResult = MatchFinder::MatchResult; using stencil::access; +using stencil::addressOf; using stencil::cat; +using stencil::deref; using stencil::dPrint; +using stencil::expression; using stencil::ifBound; using stencil::run; using stencil::text; @@ -104,7 +109,7 @@ class StencilTest : public ::testing::Test { ADD_FAILURE() << "Expected failure but succeeded: " << *ResultOrErr; } else { auto Err = llvm::handleErrors(ResultOrErr.takeError(), - [&Matcher](const llvm::StringError &Err) { + [&Matcher](const StringError &Err) { EXPECT_THAT(Err.getMessage(), Matcher); }); if (Err) { @@ -183,6 +188,15 @@ void testExpr(StringRef Id, StringRef Snippet, const Stencil &Stencil, EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), HasValue(Expected)); } +void testFailure(StringRef Id, StringRef Snippet, const Stencil &Stencil, + testing::Matcher MessageMatcher) { + auto StmtMatch = matchStmt(Snippet, expr().bind(Id)); + ASSERT_TRUE(StmtMatch); + EXPECT_THAT_EXPECTED(Stencil.eval(StmtMatch->Result), + Failed(testing::Property( + &StringError::getMessage, MessageMatcher))); +} + TEST_F(StencilTest, SelectionOp) { StringRef Id = "id"; testExpr(Id, "3;", cat(node(Id)), "3"); @@ -198,6 +212,56 @@ TEST_F(StencilTest, IfBoundOpUnbound) { testExpr(Id, "3;", cat(ifBound("other", text("5"), text("7"))), "7"); } +TEST_F(StencilTest, ExpressionOpNoParens) { + StringRef Id = "id"; + testExpr(Id, "3;", cat(expression(Id)), "3"); +} + +// Don't parenthesize a parens expression. +TEST_F(StencilTest, ExpressionOpNoParensParens) { + StringRef Id = "id"; + testExpr(Id, "(3);", cat(expression(Id)), "(3)"); +} + +TEST_F(StencilTest, ExpressionOpBinaryOpParens) { + StringRef Id = "id"; + testExpr(Id, "3+4;", cat(expression(Id)), "(3+4)"); +} + +// `expression` shares code with other ops, so we get sufficient coverage of the +// error handling code with this test. If that changes in the future, more error +// tests should be added. +TEST_F(StencilTest, ExpressionOpUnbound) { + StringRef Id = "id"; + testFailure(Id, "3;", cat(expression("ACACA")), + AllOf(HasSubstr("ACACA"), HasSubstr("not bound"))); +} + +TEST_F(StencilTest, DerefPointer) { + StringRef Id = "id"; + testExpr(Id, "int *x; x;", cat(deref(Id)), "*x"); +} + +TEST_F(StencilTest, DerefBinOp) { + StringRef Id = "id"; + testExpr(Id, "int *x; x + 1;", cat(deref(Id)), "*(x + 1)"); +} + +TEST_F(StencilTest, DerefAddressExpr) { + StringRef Id = "id"; + testExpr(Id, "int x; &x;", cat(deref(Id)), "x"); +} + +TEST_F(StencilTest, AddressOfValue) { + StringRef Id = "id"; + testExpr(Id, "int x; x;", cat(addressOf(Id)), "&x"); +} + +TEST_F(StencilTest, AddressOfDerefExpr) { + StringRef Id = "id"; + testExpr(Id, "int *x; *x;", cat(addressOf(Id)), "x"); +} + TEST_F(StencilTest, AccessOpValue) { StringRef Snippet = R"cc( S x; From 781b611af60dabbe2e497395d70792e4b8fe072e Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Thu, 3 Oct 2019 13:17:21 +0000 Subject: [PATCH 21/33] [Alignment][NFC] Remove StoreInst::setAlignment(unsigned) Summary: This is patch is part of a series to introduce an Alignment type. See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html See this patch for the introduction of the type: https://reviews.llvm.org/D64790 Reviewers: courbet, bollu, jdoerfert Subscribers: hiraditya, asbirlea, cfe-commits, llvm-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D68268 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373595 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGBuiltin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index f87a6d6ec4a6..527e512e6aac 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -11193,7 +11193,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // Unaligned nontemporal store of the scalar value. StoreInst *SI = Builder.CreateDefaultAlignedStore(Src, BC); SI->setMetadata(CGM.getModule().getMDKindID("nontemporal"), Node); - SI->setAlignment(1); + SI->setAlignment(llvm::Align::None()); return SI; } // Rotate is a special case of funnel shift - 1st 2 args are the same. From 4d78de18c1ab5dfc349bf91de1c12569a46cac79 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Thu, 3 Oct 2019 15:08:20 +0000 Subject: [PATCH 22/33] Remove duplicate P->getAs() call. NFCI. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373611 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ASTContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 99fac32210f8..2bde00403f21 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -6851,8 +6851,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, } } else if (Options.IsOutermostType()) { QualType P = PointeeTy; - while (P->getAs()) - P = P->getAs()->getPointeeType(); + while (auto PT = P->getAs()) + P = PT->getPointeeType(); if (P.isConstQualified()) { isReadOnly = true; S += 'r'; From 01df4c07433d207c101f7b39b1a0bdf3e231c9ec Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Thu, 3 Oct 2019 15:08:30 +0000 Subject: [PATCH 23/33] ExprConstant - silence static analyzer getAs<> null dereference warnings. NFCI. The static analyzer is warning about potential null dereferences, but in these cases we should be able to use castAs<> directly and if not assert will fire for us. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373612 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/ExprConstant.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index a50a67dc211c..169e7ae1e17b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -6435,9 +6435,8 @@ class BufferToAPValueConverter { QualType RepresentationType = Ty->getDecl()->getIntegerType(); assert(!RepresentationType.isNull() && "enum forward decl should be caught by Sema"); - const BuiltinType *AsBuiltin = - RepresentationType.getCanonicalType()->getAs(); - assert(AsBuiltin && "non-integral enum underlying type?"); + const auto *AsBuiltin = + RepresentationType.getCanonicalType()->castAs(); // Recurse into the underlying type. Treat std::byte transparently as // unsigned char. return visit(AsBuiltin, Offset, /*EnumTy=*/Ty); @@ -9360,7 +9359,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool VectorExprEvaluator::ZeroInitialization(const Expr *E) { - const VectorType *VT = E->getType()->getAs(); + const auto *VT = E->getType()->castAs(); QualType EltTy = VT->getElementType(); APValue ZeroElement; if (EltTy->isIntegerType()) @@ -11836,7 +11835,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { Info.CCEDiag(E, diag::note_constexpr_pointer_subtraction_not_same_array); QualType Type = E->getLHS()->getType(); - QualType ElementType = Type->getAs()->getPointeeType(); + QualType ElementType = Type->castAs()->getPointeeType(); CharUnits ElementSize; if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize)) @@ -12733,9 +12732,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { if (!Visit(E->getSubExpr())) return false; - QualType To = E->getType()->getAs()->getElementType(); + QualType To = E->getType()->castAs()->getElementType(); QualType From - = E->getSubExpr()->getType()->getAs()->getElementType(); + = E->getSubExpr()->getType()->castAs()->getElementType(); return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) && HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag); @@ -12745,9 +12744,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { if (!Visit(E->getSubExpr())) return false; - QualType To = E->getType()->getAs()->getElementType(); + QualType To = E->getType()->castAs()->getElementType(); QualType From - = E->getSubExpr()->getType()->getAs()->getElementType(); + = E->getSubExpr()->getType()->castAs()->getElementType(); Result.makeComplexInt(); return HandleFloatToIntCast(Info, E, From, Result.FloatReal, To, Result.IntReal) && @@ -12769,9 +12768,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { if (!Visit(E->getSubExpr())) return false; - QualType To = E->getType()->getAs()->getElementType(); + QualType To = E->getType()->castAs()->getElementType(); QualType From - = E->getSubExpr()->getType()->getAs()->getElementType(); + = E->getSubExpr()->getType()->castAs()->getElementType(); Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal); Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag); From c0fc42a970aa51697535fca51886cccad066329b Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Thu, 3 Oct 2019 15:10:47 +0000 Subject: [PATCH 24/33] Fix MSVC "result of 32-bit shift implicitly converted to 64 bits" warning. NFCI. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373613 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenModule.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 6370561b83a0..f8b4ffa024f2 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1600,7 +1600,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, if (!D->hasAttr()) if (LangOpts.FunctionAlignment) - F->setAlignment(llvm::Align(1 << LangOpts.FunctionAlignment)); + F->setAlignment(llvm::Align(1ull << LangOpts.FunctionAlignment)); // Some C++ ABIs require 2-byte alignment for member functions, in order to // reserve a bit for differentiating between virtual and non-virtual member From eef8c44f96699ab841d07e4f193063779fc1739a Mon Sep 17 00:00:00 2001 From: David Bolvansky Date: Thu, 3 Oct 2019 15:17:59 +0000 Subject: [PATCH 25/33] [Diagnostics] Bitwise negation of a boolean expr always evaluates to true; warn with -Wbool-operation Requested here: http://lists.llvm.org/pipermail/cfe-dev/2019-October/063452.html git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373614 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaExpr.cpp | 4 +++- test/Sema/warn-bitwise-negation-bool.c | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/Sema/warn-bitwise-negation-bool.c diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index dceef8152947..d75c8240a1c5 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -13470,7 +13470,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Input.isInvalid()) return ExprError(); resultType = Input.get()->getType(); - if (resultType->isDependentType()) break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. @@ -13478,6 +13477,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) << resultType << Input.get()->getSourceRange(); + else if (Input.get()->IgnoreParenImpCasts()->getType()->isBooleanType()) + Diag(OpLoc, diag::warn_bitwise_negation_bool) + << FixItHint::CreateReplacement(OpLoc, "!"); else if (resultType->hasIntegerRepresentation()) break; else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) { diff --git a/test/Sema/warn-bitwise-negation-bool.c b/test/Sema/warn-bitwise-negation-bool.c new file mode 100644 index 000000000000..1d39f0c576f8 --- /dev/null +++ b/test/Sema/warn-bitwise-negation-bool.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wbool-operation %s +// RUN: %clang_cc1 -x c -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wbool-operation %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +#ifdef __cplusplus +typedef bool boolean; +#else +typedef _Bool boolean; +#endif + +void test(boolean b, int i) { + b = ~b; // expected-warning {{bitwise negation of a boolean expression always evaluates to 'true'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:8}:"!" + b = ~(b); // expected-warning {{bitwise negation of a boolean expression always evaluates to 'true'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:7-[[@LINE-1]]:8}:"!" + b = ~i; +} From 0eeebf8d680e38052455fcc8292d30a5bf365db0 Mon Sep 17 00:00:00 2001 From: David Bolvansky Date: Thu, 3 Oct 2019 15:26:26 +0000 Subject: [PATCH 26/33] [NFC] Added missing changes for rL373614 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373616 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2ccd3090a477..80d8858de961 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6635,6 +6635,9 @@ def note_member_declared_here : Note< "member %0 declared here">; def note_member_first_declared_here : Note< "member %0 first declared here">; +def warn_bitwise_negation_bool : Warning< + "bitwise negation of a boolean expression always evaluates to 'true'">, + InGroup>; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated and " From a890b574da851b2367279d7aebdb28ce478e2b35 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Thu, 3 Oct 2019 16:20:34 +0000 Subject: [PATCH 27/33] [OPENMP]Improve diagnostics for not found declare target entries. We can point to the target region + emit parent functions names/real var names if they were not found in host module during device codegen. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373620 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGOpenMPRuntime.cpp | 47 ++++++++++++++++++++++----------- test/OpenMP/target_messages.cpp | 6 ++--- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 4da84f230ec1..f64f39defb51 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4201,7 +4201,9 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { llvm::Module &M = CGM.getModule(); llvm::LLVMContext &C = M.getContext(); - SmallVector + SmallVector, + 16> OrderedEntries(OffloadEntriesInfoManager.size()); llvm::SmallVector ParentFunctions( OffloadEntriesInfoManager.size()); @@ -4219,7 +4221,8 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { // Create function that emits metadata for each target region entry; auto &&TargetRegionMetadataEmitter = - [&C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt, &GetMDString]( + [this, &C, MD, &OrderedEntries, &ParentFunctions, &GetMDInt, + &GetMDString]( unsigned DeviceID, unsigned FileID, StringRef ParentName, unsigned Line, const OffloadEntriesInfoManagerTy::OffloadEntryInfoTargetRegion &E) { @@ -4237,8 +4240,19 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { GetMDInt(FileID), GetMDString(ParentName), GetMDInt(Line), GetMDInt(E.getOrder())}; + SourceLocation Loc; + for (auto I = CGM.getContext().getSourceManager().fileinfo_begin(), + E = CGM.getContext().getSourceManager().fileinfo_end(); + I != E; ++I) { + if (I->getFirst()->getUniqueID().getDevice() == DeviceID && + I->getFirst()->getUniqueID().getFile() == FileID) { + Loc = CGM.getContext().getSourceManager().translateFileLineCol( + I->getFirst(), Line, 1); + break; + } + } // Save this entry in the right position of the ordered entries array. - OrderedEntries[E.getOrder()] = &E; + OrderedEntries[E.getOrder()] = std::make_tuple(&E, Loc, ParentName); ParentFunctions[E.getOrder()] = ParentName; // Add metadata to the named metadata node. @@ -4266,7 +4280,8 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { GetMDInt(E.getFlags()), GetMDInt(E.getOrder())}; // Save this entry in the right position of the ordered entries array. - OrderedEntries[E.getOrder()] = &E; + OrderedEntries[E.getOrder()] = + std::make_tuple(&E, SourceLocation(), MangledName); // Add metadata to the named metadata node. MD->addOperand(llvm::MDNode::get(C, Ops)); @@ -4275,11 +4290,11 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { OffloadEntriesInfoManager.actOnDeviceGlobalVarEntriesInfo( DeviceGlobalVarMetadataEmitter); - for (const auto *E : OrderedEntries) { - assert(E && "All ordered entries must exist!"); + for (const auto &E : OrderedEntries) { + assert(std::get<0>(E) && "All ordered entries must exist!"); if (const auto *CE = dyn_cast( - E)) { + std::get<0>(E))) { if (!CE->getID() || !CE->getAddress()) { // Do not blame the entry if the parent funtion is not emitted. StringRef FnName = ParentFunctions[CE->getOrder()]; @@ -4287,16 +4302,16 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { continue; unsigned DiagID = CGM.getDiags().getCustomDiagID( DiagnosticsEngine::Error, - "Offloading entry for target region is incorrect: either the " + "Offloading entry for target region in %0 is incorrect: either the " "address or the ID is invalid."); - CGM.getDiags().Report(DiagID); + CGM.getDiags().Report(std::get<1>(E), DiagID) << FnName; continue; } createOffloadEntry(CE->getID(), CE->getAddress(), /*Size=*/0, CE->getFlags(), llvm::GlobalValue::WeakAnyLinkage); - } else if (const auto *CE = - dyn_cast(E)) { + } else if (const auto *CE = dyn_cast( + std::get<0>(E))) { OffloadEntriesInfoManagerTy::OMPTargetGlobalVarEntryKind Flags = static_cast( CE->getFlags()); @@ -4307,10 +4322,10 @@ void CGOpenMPRuntime::createOffloadEntriesAndInfoMetadata() { continue; if (!CE->getAddress()) { unsigned DiagID = CGM.getDiags().getCustomDiagID( - DiagnosticsEngine::Error, - "Offloading entry for declare target variable is incorrect: the " - "address is invalid."); - CGM.getDiags().Report(DiagID); + DiagnosticsEngine::Error, "Offloading entry for declare target " + "variable %0 is incorrect: the " + "address is invalid."); + CGM.getDiags().Report(std::get<1>(E), DiagID) << std::get<2>(E); continue; } // The vaiable has no definition - no need to add the entry. diff --git a/test/OpenMP/target_messages.cpp b/test/OpenMP/target_messages.cpp index 9bd8b3749e05..5f22fbcaf606 100644 --- a/test/OpenMP/target_messages.cpp +++ b/test/OpenMP/target_messages.cpp @@ -13,14 +13,12 @@ // NO-HOST-BC: The provided host compiler IR file '1111.bc' is required to generate code for OpenMP target regions but cannot be found. // RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc -DREGION_HOST -// RUN: not %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -DREGION_DEVICE 2>&1 | FileCheck %s --check-prefix NO-REGION -// NO-REGION: Offloading entry for target region is incorrect: either the address or the ID is invalid. -// NO-REGION-NOT: Offloading entry for target region is incorrect: either the address or the ID is invalid. +// RUN: not %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -DREGION_DEVICE 2>&1 #if defined(REGION_HOST) || defined(REGION_DEVICE) void foo() { #ifdef REGION_HOST -#pragma omp target +#pragma omp target // expected-error {{Offloading entry for target region in _Z3foov is incorrect: either the address or the ID is invalid.}} ; #endif #ifdef REGION_DEVICE From 2734b155fee2b4b9c79770b1d754efcfcd406f34 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Thu, 3 Oct 2019 16:46:49 +0000 Subject: [PATCH 28/33] [OPENMP]Fix emission of the declare target variables in device mode. Declare target variables must be emitted in device mode, target triples can be empty in this case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373624 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGOpenMPRuntime.cpp | 6 ++++-- test/OpenMP/declare_target_codegen.cpp | 23 ++++++++--------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index f64f39defb51..27231dbf9b3c 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -2868,7 +2868,8 @@ llvm::Function *CGOpenMPRuntime::emitThreadPrivateVarDefinition( bool CGOpenMPRuntime::emitDeclareTargetVarDefinition(const VarDecl *VD, llvm::GlobalVariable *Addr, bool PerformInit) { - if (CGM.getLangOpts().OMPTargetTriples.empty()) + if (CGM.getLangOpts().OMPTargetTriples.empty() && + !CGM.getLangOpts().OpenMPIsDevice) return false; Optional Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); @@ -9806,7 +9807,8 @@ CGOpenMPRuntime::registerTargetFirstprivateCopy(CodeGenFunction &CGF, void CGOpenMPRuntime::registerTargetGlobalVariable(const VarDecl *VD, llvm::Constant *Addr) { - if (CGM.getLangOpts().OMPTargetTriples.empty()) + if (CGM.getLangOpts().OMPTargetTriples.empty() && + !CGM.getLangOpts().OpenMPIsDevice) return; llvm::Optional Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); diff --git a/test/OpenMP/declare_target_codegen.cpp b/test/OpenMP/declare_target_codegen.cpp index dd4ab3c8248e..f1074ee5b294 100644 --- a/test/OpenMP/declare_target_codegen.cpp +++ b/test/OpenMP/declare_target_codegen.cpp @@ -1,29 +1,22 @@ // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -emit-pch -o %t -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -emit-pch -o %t +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -o - | FileCheck %s // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix HOST5 // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc -fopenmp-version=50 -DOMP5 -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix DEV5 +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix DEV5 // RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix KMPC-ONLY -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm-bc %s -o %t-ppc-host.bc -fopenmp-version=50 -DOMP5 -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix KMPC-ONLY - -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm-bc %s -o %t-ppc-host.bc -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o -| FileCheck %s --check-prefix KMPC-ONLY -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -emit-pch -o %t -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify -o - | FileCheck %s --check-prefix KMPC-ONLY // RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix SIMD-ONLY // RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc -fopenmp-version=50 -DOMP5 -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix SIMD-ONLY +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fopenmp-version=50 -DOMP5 | FileCheck %s --check-prefix SIMD-ONLY // RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm-bc %s -o %t-ppc-host.bc -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o -| FileCheck %s --check-prefix SIMD-ONLY -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -emit-pch -o %t -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=powerpc64le-ibm-linux-gnu -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify -o - | FileCheck %s --check-prefix SIMD-ONLY +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o -| FileCheck %s --check-prefix SIMD-ONLY +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -emit-pch -o %t +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -include-pch %t -verify -o - | FileCheck %s --check-prefix SIMD-ONLY // expected-no-diagnostics From f294fc0727d7d1db043d33162c78d94333572761 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Thu, 3 Oct 2019 16:58:01 +0000 Subject: [PATCH 29/33] DeclBase/DeclCXX/DeclTemplate - silence static analyzer getAs<> null dereference warnings. NFCI. The static analyzer is warning about potential null dereferences, but in these cases we should be able to use castAs<> directly and if not assert will fire for us. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373626 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/AST/DeclBase.cpp | 6 +++--- lib/AST/DeclCXX.cpp | 2 +- lib/AST/DeclTemplate.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 10537efebfc7..77a3a4c679a1 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -959,11 +959,11 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const { return nullptr; if (Ty->isFunctionPointerType()) - Ty = Ty->getAs()->getPointeeType(); + Ty = Ty->castAs()->getPointeeType(); else if (Ty->isFunctionReferenceType()) - Ty = Ty->getAs()->getPointeeType(); + Ty = Ty->castAs()->getPointeeType(); else if (BlocksToo && Ty->isBlockPointerType()) - Ty = Ty->getAs()->getPointeeType(); + Ty = Ty->castAs()->getPointeeType(); return Ty->getAs(); } diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 3602f1189e97..a085941e68c5 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -2566,7 +2566,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { return false; return (getNumParams() == 0 && - getType()->getAs()->isVariadic()) || + getType()->castAs()->isVariadic()) || (getNumParams() == 1) || (getNumParams() > 1 && (getParamDecl(1)->hasDefaultArg() || diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index c03ae22fb5d8..ccfc292e4c6c 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -519,15 +519,15 @@ SourceRange TemplateTypeParmDecl::getSourceRange() const { } unsigned TemplateTypeParmDecl::getDepth() const { - return getTypeForDecl()->getAs()->getDepth(); + return getTypeForDecl()->castAs()->getDepth(); } unsigned TemplateTypeParmDecl::getIndex() const { - return getTypeForDecl()->getAs()->getIndex(); + return getTypeForDecl()->castAs()->getIndex(); } bool TemplateTypeParmDecl::isParameterPack() const { - return getTypeForDecl()->getAs()->isParameterPack(); + return getTypeForDecl()->castAs()->isParameterPack(); } //===----------------------------------------------------------------------===// From 488d876b0a3f5aedb4e605d17074051e0faaaa1f Mon Sep 17 00:00:00 2001 From: Michael Liao Date: Thu, 3 Oct 2019 17:49:20 +0000 Subject: [PATCH 30/33] [HIP] Enable specifying different default gpu arch for HIP/CUDA. Reviewers: tra, yaxunl Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D68394 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373634 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Driver/Driver.cpp | 14 +++++++++++--- test/Driver/hip-default-gpu-arch.hip | 7 +++++++ 2 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 test/Driver/hip-default-gpu-arch.hip diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 8fc3db8c8348..73b258331f79 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2329,6 +2329,10 @@ class OffloadingActionBuilder final { /// Flag for -fgpu-rdc. bool Relocatable = false; + + /// Default GPU architecture if there's no one specified. + CudaArch DefaultCudaArch = CudaArch::UNKNOWN; + public: CudaActionBuilderBase(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs, @@ -2518,7 +2522,7 @@ class OffloadingActionBuilder final { // supported GPUs. sm_20 code should work correctly, if // suboptimally, on all newer GPUs. if (GpuArchList.empty()) - GpuArchList.push_back(CudaArch::SM_20); + GpuArchList.push_back(DefaultCudaArch); return Error; } @@ -2530,7 +2534,9 @@ class OffloadingActionBuilder final { public: CudaActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) - : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) {} + : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) { + DefaultCudaArch = CudaArch::SM_20; + } ActionBuilderReturnCode getDeviceDependences(OffloadAction::DeviceDependences &DA, @@ -2645,7 +2651,9 @@ class OffloadingActionBuilder final { public: HIPActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) - : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) {} + : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { + DefaultCudaArch = CudaArch::GFX803; + } bool canUseBundlerUnbundler() const override { return true; } diff --git a/test/Driver/hip-default-gpu-arch.hip b/test/Driver/hip-default-gpu-arch.hip new file mode 100644 index 000000000000..56e36882dc63 --- /dev/null +++ b/test/Driver/hip-default-gpu-arch.hip @@ -0,0 +1,7 @@ +// REQUIRES: clang-driver +// REQUIRES: x86-registered-target +// REQUIRES: amdgpu-registered-target + +// RUN: %clang -### -x hip -c %s 2>&1 | FileCheck %s + +// CHECK: {{.*}}clang{{.*}}"-target-cpu" "gfx803" From cf3ce1cf84cfd9f639a905a9e13047cf45cd9af6 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 18:24:40 +0000 Subject: [PATCH 31/33] PR43547: substitute into the type of a non-type template parameter if it's instantiation-dependent, even if it's not dependent. There might be a SFINAE check in the parameter type. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373643 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaTemplate.cpp | 4 +--- test/SemaTemplate/temp_arg_nontype.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index e189b5235a97..847a19baed14 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4922,9 +4922,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (NTTP->isParameterPack() && NTTP->isExpandedParameterPack()) NTTPType = NTTP->getExpansionType(ArgumentPackIndex); - // FIXME: Do we need to substitute into parameters here if they're - // instantiation-dependent but not dependent? - if (NTTPType->isDependentType() && + if (NTTPType->isInstantiationDependentType() && !isa(Template) && !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. diff --git a/test/SemaTemplate/temp_arg_nontype.cpp b/test/SemaTemplate/temp_arg_nontype.cpp index bdf766331252..3249d0dc1941 100644 --- a/test/SemaTemplate/temp_arg_nontype.cpp +++ b/test/SemaTemplate/temp_arg_nontype.cpp @@ -482,3 +482,15 @@ namespace dependent_backreference { template void a() { X x; } template void b() { X x; } // expected-note {{substituting}} } + +namespace instantiation_dependent { + template void f(int); + template int &f(...); + int &rf = f(0); + + // FIXME: This fails because we mishandle instantiation-dependent array bounds :( + int arr[sizeof(sizeof(int))]; + template void g(int); + template int &g(...); + int &rg = g(0); // expected-error {{cannot bind}} +} From 04d93a17d3b65dff10fe481ae254b7137030400c Mon Sep 17 00:00:00 2001 From: Paul Hoad Date: Thu, 3 Oct 2019 18:42:31 +0000 Subject: [PATCH 32/33] [clang-format] Add ability to wrap braces after multi-line control statements Summary: Change the BraceWrappingFlags' AfterControlStatement from a bool to an enum with three values: * "Never": This is the default, and does not do any brace wrapping after control statements. * "MultiLine": This only wraps braces after multi-line control statements (this really only happens when a ColumnLimit is specified). * "Always": This always wraps braces after control statements. The first and last options are backwards-compatible with "false" and "true", respectively. The new "MultiLine" option is useful for when a wrapped control statement's indentation matches the subsequent block's indentation. It makes it easier to see at a glance where the control statement ends and where the block's code begins. For example: ``` if ( foo && bar ) { baz(); } ``` vs. ``` if ( foo && bar ) { baz(); } ``` Short control statements (1 line) do not wrap the brace to the next line, e.g. ``` if (foo) { bar(); } else { baz(); } ``` Reviewers: sammccall, owenpan, reuk, MyDeveloperDay, klimek Reviewed By: MyDeveloperDay Subscribers: MyDeveloperDay, cfe-commits Patch By: mitchell-stellar Tags: #clang-format, #clang, #clang-tools-extra Differential Revision: https://reviews.llvm.org/D68296 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373647 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ClangFormatStyleOptions.rst | 52 ++++++--- include/clang/Format/Format.h | 52 ++++++--- lib/Format/Format.cpp | 46 ++++++-- lib/Format/UnwrappedLineFormatter.cpp | 44 ++++++-- lib/Format/UnwrappedLineParser.cpp | 9 +- unittests/Format/FormatTest.cpp | 154 +++++++++++++++++++++++++- unittests/Format/FormatTestObjC.cpp | 4 +- 7 files changed, 301 insertions(+), 60 deletions(-) diff --git a/docs/ClangFormatStyleOptions.rst b/docs/ClangFormatStyleOptions.rst index 0803e65df2e2..c7f47c5c021e 100644 --- a/docs/ClangFormatStyleOptions.rst +++ b/docs/ClangFormatStyleOptions.rst @@ -778,24 +778,46 @@ the configuration (without a prefix: ``Auto``). class foo {}; - * ``bool AfterControlStatement`` Wrap control statements (``if``/``for``/``while``/``switch``/..). + * ``BraceWrappingAfterControlStatementStyle AfterControlStatement`` + Wrap control statements (``if``/``for``/``while``/``switch``/..). - .. code-block:: c++ + Possible values: - true: - if (foo()) - { - } else - {} - for (int i = 0; i < 10; ++i) - {} + * ``BWACS_Never`` (in configuration: ``Never``) + Never wrap braces after a control statement. - false: - if (foo()) { - } else { - } - for (int i = 0; i < 10; ++i) { - } + .. code-block:: c++ + + if (foo()) { + } else { + } + for (int i = 0; i < 10; ++i) { + } + + * ``BWACS_MultiLine`` (in configuration: ``MultiLine``) + Only wrap braces after a multi-line control statement. + + .. code-block:: c++ + + if (foo && bar && + baz) + { + quux(); + } + while (foo || bar) { + } + + * ``BWACS_Always`` (in configuration: ``Always``) + Always wrap braces after a control statement. + + .. code-block:: c++ + + if (foo()) + { + } else + {} + for (int i = 0; i < 10; ++i) + {} * ``bool AfterEnum`` Wrap enum definitions. diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 6389e498e483..d774c04b6de5 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -782,6 +782,40 @@ struct FormatStyle { /// The brace breaking style to use. BraceBreakingStyle BreakBeforeBraces; + // Different ways to wrap braces after control statements. + enum BraceWrappingAfterControlStatementStyle { + /// Never wrap braces after a control statement. + /// \code + /// if (foo()) { + /// } else { + /// } + /// for (int i = 0; i < 10; ++i) { + /// } + /// \endcode + BWACS_Never, + /// Only wrap braces after a multi-line control statement. + /// \code + /// if (foo && bar && + /// baz) + /// { + /// quux(); + /// } + /// while (foo || bar) { + /// } + /// \endcode + BWACS_MultiLine, + /// Always wrap braces after a control statement. + /// \code + /// if (foo()) + /// { + /// } else + /// {} + /// for (int i = 0; i < 10; ++i) + /// {} + /// \endcode + BWACS_Always + }; + /// Precise control over the wrapping of braces. /// \code /// # Should be declared this way: @@ -817,23 +851,7 @@ struct FormatStyle { /// \endcode bool AfterClass; /// Wrap control statements (``if``/``for``/``while``/``switch``/..). - /// \code - /// true: - /// if (foo()) - /// { - /// } else - /// {} - /// for (int i = 0; i < 10; ++i) - /// {} - /// - /// false: - /// if (foo()) { - /// } else { - /// } - /// for (int i = 0; i < 10; ++i) { - /// } - /// \endcode - bool AfterControlStatement; + BraceWrappingAfterControlStatementStyle AfterControlStatement; /// Wrap enum definitions. /// \code /// true: diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index dd561cc0d892..5b267784ff1e 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -181,6 +181,20 @@ template <> struct ScalarEnumerationTraits { } }; +template <> +struct ScalarEnumerationTraits< + FormatStyle::BraceWrappingAfterControlStatementStyle> { + static void + enumeration(IO &IO, + FormatStyle::BraceWrappingAfterControlStatementStyle &Value) { + IO.enumCase(Value, "false", FormatStyle::BWACS_Never); + IO.enumCase(Value, "true", FormatStyle::BWACS_Always); + IO.enumCase(Value, "Never", FormatStyle::BWACS_Never); + IO.enumCase(Value, "MultiLine", FormatStyle::BWACS_MultiLine); + IO.enumCase(Value, "Always", FormatStyle::BWACS_Always); + } +}; + template <> struct ScalarEnumerationTraits { static void @@ -629,9 +643,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) { if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) return Style; FormatStyle Expanded = Style; - Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, false, - false, true, true, true}; + Expanded.BraceWrapping = {false, false, FormatStyle::BWACS_Never, + false, false, false, + false, false, false, + false, false, false, + false, true, true, + true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -656,7 +673,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { case FormatStyle::BS_Allman: Expanded.BraceWrapping.AfterCaseLabel = true; Expanded.BraceWrapping.AfterClass = true; - Expanded.BraceWrapping.AfterControlStatement = true; + Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Expanded.BraceWrapping.AfterEnum = true; Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterNamespace = true; @@ -670,7 +687,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { case FormatStyle::BS_Whitesmiths: Expanded.BraceWrapping.AfterCaseLabel = true; Expanded.BraceWrapping.AfterClass = true; - Expanded.BraceWrapping.AfterControlStatement = true; + Expanded.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Expanded.BraceWrapping.AfterEnum = true; Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterNamespace = true; @@ -681,8 +698,12 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.BeforeElse = true; break; case FormatStyle::BS_GNU: - Expanded.BraceWrapping = {true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true}; + Expanded.BraceWrapping = {true, true, FormatStyle::BWACS_Always, + true, true, true, + true, true, true, + true, true, true, + true, true, true, + true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -722,9 +743,12 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; - LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false, false, - false, true, true, true}; + LLVMStyle.BraceWrapping = {false, false, FormatStyle::BWACS_Never, + false, false, false, + false, false, false, + false, false, false, + false, true, true, + true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; @@ -1067,7 +1091,7 @@ FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) { Style.UseTab = FormatStyle::UT_Never; Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterClass = true; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Style.BraceWrapping.AfterEnum = true; Style.BraceWrapping.AfterFunction = true; Style.BraceWrapping.AfterNamespace = true; diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index df30f7db80e6..8b8d357d9cbe 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -306,8 +306,24 @@ class LineJoiner { } // Try to merge a control statement block with left brace wrapped if (I[1]->First->is(tok::l_brace) && - TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for)) { - return Style.BraceWrapping.AfterControlStatement + (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, + tok::kw_switch, tok::kw_try, tok::kw_do) || + (TheLine->First->is(tok::r_brace) && TheLine->First->Next && + TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) { + // If possible, merge the next line's wrapped left brace with the current + // line. Otherwise, leave it on the next line, as this is a multi-line + // control statement. + return (Style.ColumnLimit == 0 || + TheLine->Last->TotalLength <= Style.ColumnLimit) + ? 1 + : 0; + } else if (I[1]->First->is(tok::l_brace) && + TheLine->First->isOneOf(tok::kw_if, tok::kw_while, + tok::kw_for)) { + return (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) ? tryMergeSimpleBlock(I, E, Limit) : 0; } @@ -410,7 +426,8 @@ class LineJoiner { SmallVectorImpl::const_iterator E, unsigned Limit) { if (Limit == 0) return 0; - if (Style.BraceWrapping.AfterControlStatement && + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && I[1]->First->is(tok::l_brace) && Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return 0; @@ -523,8 +540,9 @@ class LineJoiner { return 0; if (!Style.AllowShortIfStatementsOnASingleLine && Line.startsWith(tok::kw_if) && - Style.BraceWrapping.AfterControlStatement && I + 2 != E && - !I[2]->First->is(tok::r_brace)) + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && + I + 2 != E && !I[2]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && @@ -533,8 +551,9 @@ class LineJoiner { return 0; if (!Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for) && - Style.BraceWrapping.AfterControlStatement && I + 2 != E && - !I[2]->First->is(tok::r_brace)) + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always && + I + 2 != E && !I[2]->First->is(tok::r_brace)) return 0; // FIXME: Consider an option to allow short exception handling clauses on // a single line. @@ -597,6 +616,17 @@ class LineJoiner { if (Tok->Next && Tok->Next->is(tok::kw_else)) return 0; + // Don't merge a trailing multi-line control statement block like: + // } else if (foo && + // bar) + // { <-- current Line + // baz(); + // } + if (Line.First == Line.Last && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) + return 0; + return 2; } } else if (I[1]->First->is(tok::l_brace)) { diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 8fd0e9433b63..bbe05602f6da 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -1167,7 +1167,8 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::objc_autoreleasepool: nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/false); } @@ -1179,7 +1180,8 @@ void UnwrappedLineParser::parseStructuralElement() { // Skip synchronization object parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseBlock(/*MustBeDeclaration=*/false); } @@ -1989,7 +1991,8 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { Style.BraceWrapping.IndentBraces); parseBlock(/*MustBeDeclaration=*/false); if (FormatTok->Tok.is(tok::kw_break)) { - if (Style.BraceWrapping.AfterControlStatement) + if (Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_Always) addUnwrappedLine(); parseStructuralElement(); } diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index d7759bc6df3b..e982c8b2ab07 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -644,7 +644,8 @@ TEST_F(FormatTest, FormatShortBracedStatements) { AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse; AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true; - AllowSimpleBracedStatements.BraceWrapping.AfterControlStatement = true; + AllowSimpleBracedStatements.BraceWrapping.AfterControlStatement = + FormatStyle::BWACS_Always; verifyFormat("if (true) {}", AllowSimpleBracedStatements); verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements); @@ -1168,7 +1169,7 @@ TEST_F(FormatTest, FormatsSwitchStatement) { Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterCaseLabel = true; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; EXPECT_EQ("switch (n)\n" "{\n" " case 0:\n" @@ -1370,7 +1371,7 @@ TEST_F(FormatTest, ShortCaseLabels) { Style.AllowShortCaseLabelsOnASingleLine = true; Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterCaseLabel = true; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; EXPECT_EQ("switch (n)\n" "{\n" " case 0:\n" @@ -1441,6 +1442,131 @@ TEST_F(FormatTest, FormatsLabels) { "}"); } +TEST_F(FormatTest, MultiLineControlStatements) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBraces = FormatStyle::BraceBreakingStyle::BS_Custom; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_MultiLine; + Style.ColumnLimit = 20; + // Short lines should keep opening brace on same line. + EXPECT_EQ("if (foo) {\n" + " bar();\n" + "}", + format("if(foo){bar();}", Style)); + EXPECT_EQ("if (foo) {\n" + " bar();\n" + "} else {\n" + " baz();\n" + "}", + format("if(foo){bar();}else{baz();}", Style)); + EXPECT_EQ("if (foo && bar) {\n" + " baz();\n" + "}", + format("if(foo&&bar){baz();}", Style)); + EXPECT_EQ("if (foo) {\n" + " bar();\n" + "} else if (baz) {\n" + " quux();\n" + "}", + format("if(foo){bar();}else if(baz){quux();}", Style)); + EXPECT_EQ( + "if (foo) {\n" + " bar();\n" + "} else if (baz) {\n" + " quux();\n" + "} else {\n" + " foobar();\n" + "}", + format("if(foo){bar();}else if(baz){quux();}else{foobar();}", Style)); + EXPECT_EQ("for (;;) {\n" + " foo();\n" + "}", + format("for(;;){foo();}")); + EXPECT_EQ("while (1) {\n" + " foo();\n" + "}", + format("while(1){foo();}", Style)); + EXPECT_EQ("switch (foo) {\n" + "case bar:\n" + " return;\n" + "}", + format("switch(foo){case bar:return;}", Style)); + EXPECT_EQ("try {\n" + " foo();\n" + "} catch (...) {\n" + " bar();\n" + "}", + format("try{foo();}catch(...){bar();}", Style)); + EXPECT_EQ("do {\n" + " foo();\n" + "} while (bar &&\n" + " baz);", + format("do{foo();}while(bar&&baz);", Style)); + // Long lines should put opening brace on new line. + EXPECT_EQ("if (foo && bar &&\n" + " baz)\n" + "{\n" + " quux();\n" + "}", + format("if(foo&&bar&&baz){quux();}", Style)); + EXPECT_EQ("if (foo && bar &&\n" + " baz)\n" + "{\n" + " quux();\n" + "}", + format("if (foo && bar &&\n" + " baz) {\n" + " quux();\n" + "}", + Style)); + EXPECT_EQ("if (foo) {\n" + " bar();\n" + "} else if (baz ||\n" + " quux)\n" + "{\n" + " foobar();\n" + "}", + format("if(foo){bar();}else if(baz||quux){foobar();}", Style)); + EXPECT_EQ( + "if (foo) {\n" + " bar();\n" + "} else if (baz ||\n" + " quux)\n" + "{\n" + " foobar();\n" + "} else {\n" + " barbaz();\n" + "}", + format("if(foo){bar();}else if(baz||quux){foobar();}else{barbaz();}", + Style)); + EXPECT_EQ("for (int i = 0;\n" + " i < 10; ++i)\n" + "{\n" + " foo();\n" + "}", + format("for(int i=0;i<10;++i){foo();}", Style)); + EXPECT_EQ("while (foo || bar ||\n" + " baz)\n" + "{\n" + " quux();\n" + "}", + format("while(foo||bar||baz){quux();}", Style)); + EXPECT_EQ("switch (\n" + " foo = barbaz)\n" + "{\n" + "case quux:\n" + " return;\n" + "}", + format("switch(foo=barbaz){case quux:return;}", Style)); + EXPECT_EQ("try {\n" + " foo();\n" + "} catch (\n" + " Exception &bar)\n" + "{\n" + " baz();\n" + "}", + format("try{foo();}catch(Exception&bar){baz();}", Style)); +} + //===----------------------------------------------------------------------===// // Tests for classes, namespaces, etc. //===----------------------------------------------------------------------===// @@ -2940,7 +3066,7 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) { "};")); FormatStyle Style = getLLVMStyle(); Style.BreakBeforeBraces = FormatStyle::BS_Custom; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; Style.BraceWrapping.AfterFunction = true; EXPECT_EQ("void f()\n" "try\n" @@ -12261,7 +12387,6 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterCaseLabel); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass); - CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterControlStatement); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterFunction); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterNamespace); @@ -12469,6 +12594,25 @@ TEST_F(FormatTest, ParsesConfiguration) { CHECK_PARSE("BreakBeforeBraces: Custom", BreakBeforeBraces, FormatStyle::BS_Custom); + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Never; + CHECK_PARSE("BraceWrapping:\n" + " AfterControlStatement: MultiLine", + BraceWrapping.AfterControlStatement, + FormatStyle::BWACS_MultiLine); + CHECK_PARSE("BraceWrapping:\n" + " AfterControlStatement: Always", + BraceWrapping.AfterControlStatement, FormatStyle::BWACS_Always); + CHECK_PARSE("BraceWrapping:\n" + " AfterControlStatement: Never", + BraceWrapping.AfterControlStatement, FormatStyle::BWACS_Never); + // For backward compatibility: + CHECK_PARSE("BraceWrapping:\n" + " AfterControlStatement: true", + BraceWrapping.AfterControlStatement, FormatStyle::BWACS_Always); + CHECK_PARSE("BraceWrapping:\n" + " AfterControlStatement: false", + BraceWrapping.AfterControlStatement, FormatStyle::BWACS_Never); + Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_All; CHECK_PARSE("AlwaysBreakAfterReturnType: None", AlwaysBreakAfterReturnType, FormatStyle::RTBS_None); diff --git a/unittests/Format/FormatTestObjC.cpp b/unittests/Format/FormatTestObjC.cpp index 8fb93195881d..063eb5f58f1f 100644 --- a/unittests/Format/FormatTestObjC.cpp +++ b/unittests/Format/FormatTestObjC.cpp @@ -207,7 +207,7 @@ TEST_F(FormatTestObjC, FormatObjCAutoreleasepool) { " f();\n" "}\n"); Style.BreakBeforeBraces = FormatStyle::BS_Custom; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; verifyFormat("@autoreleasepool\n" "{\n" " f();\n" @@ -237,7 +237,7 @@ TEST_F(FormatTestObjC, FormatObjCSynchronized) { " f();\n" "}\n"); Style.BreakBeforeBraces = FormatStyle::BS_Custom; - Style.BraceWrapping.AfterControlStatement = true; + Style.BraceWrapping.AfterControlStatement = FormatStyle::BWACS_Always; verifyFormat("@synchronized(self)\n" "{\n" " f();\n" From c8297e1181cd7ac9a80a35f191ac1f6cc086d4ee Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 3 Oct 2019 18:55:23 +0000 Subject: [PATCH 33/33] Check for qualified function types after substituting into the operand of 'typeid'. This is a rare place where it's valid for a function type to be substituted but not valid for a qualified function type to be substituted, so needs a special check. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@373648 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 2 ++ include/clang/Sema/Sema.h | 2 ++ lib/Sema/SemaExprCXX.cpp | 3 +++ lib/Sema/SemaType.cpp | 14 +++++++++++++- test/SemaTemplate/instantiate-expr-4.cpp | 9 +++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 80d8858de961..b167f465d9ea 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6211,6 +6211,8 @@ def err_invalid_qualified_function_type : Error< def err_compound_qualified_function_type : Error< "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1" "cannot have '%3' qualifier">; +def err_qualified_function_typeid : Error< + "type operand %0 of 'typeid' cannot have '%1' qualifier">; def err_ref_qualifier_overload : Error< "cannot overload a member function %select{without a ref-qualifier|with " diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 1e763bdf8d97..402ee4f858af 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1522,6 +1522,8 @@ class Sema { QualType BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, SourceLocation AttrLoc); + bool CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc); + bool CheckFunctionReturnType(QualType T, SourceLocation Loc); /// Build a function type. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index abd8745277a5..a25e86b95c37 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -453,6 +453,9 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, if (T->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); + if (CheckQualifiedFunctionForTypeId(T, TypeidLoc)) + return ExprError(); + return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index a9459d97942f..3029e148dc10 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1955,7 +1955,8 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, QualifiedFunctionKind QFK) { // Does T refer to a function type with a cv-qualifier or a ref-qualifier? const FunctionProtoType *FPT = T->getAs(); - if (!FPT || (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + if (!FPT || + (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) return false; S.Diag(Loc, diag::err_compound_qualified_function_type) @@ -1964,6 +1965,17 @@ static bool checkQualifiedFunction(Sema &S, QualType T, SourceLocation Loc, return true; } +bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) { + const FunctionProtoType *FPT = T->getAs(); + if (!FPT || + (FPT->getMethodQuals().empty() && FPT->getRefQualifier() == RQ_None)) + return false; + + Diag(Loc, diag::err_qualified_function_typeid) + << T << getFunctionQualifiersAsString(FPT); + return true; +} + /// Build a pointer type. /// /// \param T The type to which we'll be building a pointer. diff --git a/test/SemaTemplate/instantiate-expr-4.cpp b/test/SemaTemplate/instantiate-expr-4.cpp index 055f37bb05fe..6b4eb12755fd 100644 --- a/test/SemaTemplate/instantiate-expr-4.cpp +++ b/test/SemaTemplate/instantiate-expr-4.cpp @@ -192,6 +192,13 @@ struct TypeId0 { } }; +template +struct TypeId1 { + const std::type_info &f() { + return typeid(T); // expected-error-re 2{{type operand 'void () {{const|&}}' of 'typeid' cannot have '{{const|&}}' qualifier}} + } +}; + struct Abstract { virtual void f() = 0; }; @@ -199,6 +206,8 @@ struct Abstract { template struct TypeId0; template struct TypeId0; // expected-note{{instantiation of member function}} template struct TypeId0; +template struct TypeId1; // expected-note{{instantiation of}} +template struct TypeId1; // expected-warning 0-1{{C++11}} expected-note{{instantiation of}} // --------------------------------------------------------------------- // type traits