diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2666,6 +2666,9 @@ /// it looks like the user is trying to modify the shadowing declaration. llvm::DenseMap ShadowingDecls; + /// Determines if a variable's alignment is dependent. + static bool hasDependentAlignment(const VarDecl *VD); + public: void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -43,6 +43,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" #include @@ -13310,14 +13311,11 @@ CheckCompleteDecompositionDeclaration(DD); } -/// Determines if a variable's alignment is dependent. -static bool hasDependentAlignment(VarDecl *VD) { - if (VD->getType()->isDependentType()) - return true; - for (auto *I : VD->specific_attrs()) - if (I->isAlignmentDependent()) - return true; - return false; +bool Sema::hasDependentAlignment(const VarDecl *VD) { + return VD->getType()->isDependentType() || + llvm::any_of( + VD->specific_attrs(), + [](const AlignedAttr *AA) { return AA->isAlignmentDependent(); }); } /// Check if VD needs to be dllexport/dllimport due to being in a diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3395,7 +3395,7 @@ // Variables with higher required alignment than their type's ABI // alignment cannot use NRVO. - if (!VDType->isDependentType() && VD->hasAttr() && + if (!hasDependentAlignment(VD) && Context.getDeclAlign(VD) > Context.getTypeAlignInChars(VDType)) Info.S = NamedReturnInfo::MoveEligible; diff --git a/clang/test/CodeGen/nrvo-tracking.cpp b/clang/test/CodeGen/nrvo-tracking.cpp --- a/clang/test/CodeGen/nrvo-tracking.cpp +++ b/clang/test/CodeGen/nrvo-tracking.cpp @@ -1,9 +1,9 @@ // RUN: %clang_cc1 -std=c++20 -fblocks -Wno-return-stack-address -triple x86_64-unknown-unknown-gnu -emit-llvm -O1 -fexperimental-new-pass-manager -o - %s | FileCheck %s -struct X { - X(); - X(const X&); - X(X&&); +struct alignas(4) X { + X(); + X(const X &); + X(X &&); }; #define L(A, B, C) void l##A() { \ @@ -210,3 +210,75 @@ }; }()(); } + +namespace test_alignas { + +template X t1() { + X a [[gnu::aligned(A)]]; + return a; +} + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t1ILi1EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: ret void +template X t1<1>(); + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t1ILi4EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: ret void +template X t1<4>(); + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t1ILi8EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: call {{.*}} @_ZN1XC1EOS_ +// CHECK-NEXT: call void @llvm.lifetime.end +template X t1<8>(); + +template X t2() { + X a [[gnu::aligned(1)]] [[gnu::aligned(A)]] [[gnu::aligned(2)]]; + return a; +} + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t2ILi1EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: ret void +template X t2<1>(); + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t2ILi4EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: ret void +template X t2<4>(); + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t2ILi8EEE1Xv +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: call {{.*}} @_ZN1XC1EOS_ +// CHECK-NEXT: call void @llvm.lifetime.end +template X t2<8>(); + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t3Ev +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: ret void +X t3() { + X a [[gnu::aligned(1)]]; + return a; +} + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t4Ev +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: call {{.*}} @_ZN1XC1EOS_ +// CHECK-NEXT: call void @llvm.lifetime.end +X t4() { + X a [[gnu::aligned(8)]]; + return a; +} + +// CHECK-LABEL: define{{.*}} void @_ZN12test_alignas2t5Ev +// CHECK: call {{.*}} @_ZN1XC1Ev +// CHECK-NEXT: call {{.*}} @_ZN1XC1EOS_ +// CHECK-NEXT: call void @llvm.lifetime.end +X t5() { + X a [[gnu::aligned(1)]] [[gnu::aligned(8)]]; + return a; +} + +} // namespace test_alignas