"storage: 'omp_default_mem_alloc', 'omp_large_cap_mem_alloc', "
"'omp_const_mem_alloc', 'omp_high_bw_mem_alloc', 'omp_low_lat_mem_alloc', "
"'omp_cgroup_mem_alloc', 'omp_pteam_mem_alloc' or 'omp_thread_mem_alloc'">;
+def warn_omp_used_different_allocator : Warning<
+ "allocate directive specifies %select{default|'%1'}0 allocator while "
+ "previously used %select{default|'%3'}2">,
+ InGroup<OpenMPClauses>;
+def note_omp_previous_allocator : Note<
+ "previous allocator is specified here">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
if (isa<ParmVarDecl>(VD))
continue;
+ // If the used several times in the allocate directive, the same allocator
+ // must be used.
+ if (VD->hasAttr<OMPAllocateDeclAttr>()) {
+ const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
+ const Expr *PrevAllocator = A->getAllocator();
+ bool AllocatorsMatch = false;
+ if (Allocator && PrevAllocator) {
+ const Expr *AE = Allocator->IgnoreParenImpCasts();
+ const Expr *PAE = PrevAllocator->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID AEId, PAEId;
+ AE->Profile(AEId, Context, /*Canonical=*/true);
+ PAE->Profile(PAEId, Context, /*Canonical=*/true);
+ AllocatorsMatch = AEId == PAEId;
+ } else if (!Allocator && !PrevAllocator) {
+ AllocatorsMatch = true;
+ } else {
+ const Expr *AE = Allocator ? Allocator : PrevAllocator;
+ // In this case the specified allocator must be the default one.
+ AE = AE->IgnoreParenImpCasts();
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(AE)) {
+ DeclarationName DN = DRE->getDecl()->getDeclName();
+ AllocatorsMatch =
+ DN.isIdentifier() &&
+ DN.getAsIdentifierInfo()->isStr("omp_default_mem_alloc");
+ }
+ }
+ if (!AllocatorsMatch) {
+ SmallString<256> AllocatorBuffer;
+ llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer);
+ if (Allocator)
+ Allocator->printPretty(AllocatorStream, nullptr, getPrintingPolicy());
+ SmallString<256> PrevAllocatorBuffer;
+ llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer);
+ if (PrevAllocator)
+ PrevAllocator->printPretty(PrevAllocatorStream, nullptr,
+ getPrintingPolicy());
+
+ SourceLocation AllocatorLoc =
+ Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc();
+ SourceRange AllocatorRange =
+ Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange();
+ SourceLocation PrevAllocatorLoc =
+ PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation();
+ SourceRange PrevAllocatorRange =
+ PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange();
+ Diag(AllocatorLoc, diag::warn_omp_used_different_allocator)
+ << (Allocator ? 1 : 0) << AllocatorStream.str()
+ << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str()
+ << AllocatorRange;
+ Diag(PrevAllocatorLoc, diag::note_omp_previous_allocator)
+ << PrevAllocatorRange;
+ continue;
+ }
+ }
+
// OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++
// If a list item has a static storage type, the allocator expression in the
// allocator clause must be a constant expression that evaluates to one of
}
Vars.push_back(RefExpr);
- Attr *A = OMPAllocateDeclAttr::CreateImplicit(Context, Allocator,
- DE->getSourceRange());
- VD->addAttr(A);
- if (ASTMutationListener *ML = Context.getASTMutationListener())
- ML->DeclarationMarkedOpenMPAllocate(VD, A);
+ if ((!Allocator || (Allocator && !Allocator->isTypeDependent() &&
+ !Allocator->isValueDependent() &&
+ !Allocator->isInstantiationDependent() &&
+ !Allocator->containsUnexpandedParameterPack())) &&
+ !VD->hasAttr<OMPAllocateDeclAttr>()) {
+ Attr *A = OMPAllocateDeclAttr::CreateImplicit(Context, Allocator,
+ DE->getSourceRange());
+ VD->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPAllocate(VD, A);
+ }
}
if (Vars.empty())
return nullptr;
// CHECK-NEXT: #pragma omp allocate(St1::b) allocator(omp_default_mem_alloc){{$}}
} d;
-int a, b;
+int a, b, c;
// CHECK: int a;
// CHECK: int b;
+// CHECK: int c;
#pragma omp allocate(a) allocator(omp_large_cap_mem_alloc)
-#pragma omp allocate(a) allocator(omp_const_mem_alloc)
+#pragma omp allocate(b) allocator(omp_const_mem_alloc)
// CHECK-NEXT: #pragma omp allocate(a) allocator(omp_large_cap_mem_alloc)
-// CHECK-NEXT: #pragma omp allocate(a) allocator(omp_const_mem_alloc)
-#pragma omp allocate(d, b) allocator(omp_high_bw_mem_alloc)
-// CHECK-NEXT: #pragma omp allocate(d,b) allocator(omp_high_bw_mem_alloc)
+// CHECK-NEXT: #pragma omp allocate(b) allocator(omp_const_mem_alloc)
+#pragma omp allocate(c, d) allocator(omp_high_bw_mem_alloc)
+// CHECK-NEXT: #pragma omp allocate(c,d) allocator(omp_high_bw_mem_alloc)
template <class T>
struct ST {
#pragma omp allocate(sss) allocator(0,sss) // expected-error {{expected ')'}} expected-error {{omp_allocator_handle_t type not found; include <omp.h>}} expected-note {{to match this '('}}
#pragma omp allocate(sss) allocator(sss) // expected-error {{omp_allocator_handle_t type not found; include <omp.h>}}
-typedef void *omp_allocator_handle_t;
+typedef void **omp_allocator_handle_t;
+extern const omp_allocator_handle_t omp_thread_mem_alloc;
+extern const omp_allocator_handle_t omp_high_bw_mem_alloc;
struct St1{
int a;
static int b;
-#pragma omp allocate(b) allocator(sss) // expected-error {{initializing 'omp_allocator_handle_t' (aka 'void *') with an expression of incompatible type 'int'}}
+#pragma omp allocate(b) allocator(sss) // expected-error {{initializing 'omp_allocator_handle_t' (aka 'void **') with an expression of incompatible type 'int'}} expected-note {{previous allocator is specified here}}
+#pragma omp allocate(b)
+#pragma omp allocate(b) allocator(omp_thread_mem_alloc) // expected-warning {{allocate directive specifies 'omp_thread_mem_alloc' allocator while previously used default}}
} d; // expected-note 2 {{'d' defined here}}
// expected-error@+1 {{expected one of the predefined allocators for the variables with the static storage: 'omp_default_mem_alloc', 'omp_large_cap_mem_alloc', 'omp_const_mem_alloc', 'omp_high_bw_mem_alloc', 'omp_low_lat_mem_alloc', 'omp_cgroup_mem_alloc', 'omp_pteam_mem_alloc' or 'omp_thread_mem_alloc'}}
#pragma omp allocate(d) allocator(nullptr)
-extern void *allocator;
+extern void **allocator;
// expected-error@+1 {{expected one of the predefined allocators for the variables with the static storage: 'omp_default_mem_alloc', 'omp_large_cap_mem_alloc', 'omp_const_mem_alloc', 'omp_high_bw_mem_alloc', 'omp_low_lat_mem_alloc', 'omp_cgroup_mem_alloc', 'omp_pteam_mem_alloc' or 'omp_thread_mem_alloc'}}
#pragma omp allocate(d) allocator(allocator)
+#pragma omp allocate(d) allocator(omp_thread_mem_alloc) // expected-note {{previous allocator is specified here}}
+#pragma omp allocate(d) // expected-warning {{allocate directive specifies default allocator while previously used 'omp_thread_mem_alloc'}}
+
+int c;
+#pragma omp allocate(c) allocator(omp_thread_mem_alloc) // expected-note {{previous allocator is specified here}}
+#pragma omp allocate(c) allocator(omp_high_bw_mem_alloc) // expected-warning {{allocate directive specifies 'omp_high_bw_mem_alloc' allocator while previously used 'omp_thread_mem_alloc'}}
+