forked from OSchip/llvm-project
[Sema] Diagnose addr space mismatch while constructing objects
If we construct an object in some arbitrary non-default addr space it should fail unless either: - There is an implicit conversion from the address space to default /generic address space. - There is a matching ctor qualified with an address space that is either exactly matching or convertible to the address space of an object. Differential Revision: https://reviews.llvm.org/D62156 llvm-svn: 363944
This commit is contained in:
parent
1fffe8d6ee
commit
c25ea86d43
|
@ -3683,6 +3683,9 @@ def note_ovl_candidate_inherited_constructor_slice : Note<
|
||||||
def note_ovl_candidate_illegal_constructor : Note<
|
def note_ovl_candidate_illegal_constructor : Note<
|
||||||
"candidate %select{constructor|template}0 ignored: "
|
"candidate %select{constructor|template}0 ignored: "
|
||||||
"instantiation %select{takes|would take}0 its own class type by value">;
|
"instantiation %select{takes|would take}0 its own class type by value">;
|
||||||
|
def note_ovl_candidate_illegal_constructor_adrspace_mismatch : Note<
|
||||||
|
"candidate constructor ignored: cannot be used to construct an object "
|
||||||
|
"in address space %0">;
|
||||||
def note_ovl_candidate_bad_deduction : Note<
|
def note_ovl_candidate_bad_deduction : Note<
|
||||||
"candidate template ignored: failed template argument deduction">;
|
"candidate template ignored: failed template argument deduction">;
|
||||||
def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
|
def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
|
||||||
|
|
|
@ -723,6 +723,11 @@ class Sema;
|
||||||
/// This candidate was not viable because it is a non-default multiversioned
|
/// This candidate was not viable because it is a non-default multiversioned
|
||||||
/// function.
|
/// function.
|
||||||
ovl_non_default_multiversion_function,
|
ovl_non_default_multiversion_function,
|
||||||
|
|
||||||
|
/// This constructor/conversion candidate fail due to an address space
|
||||||
|
/// mismatch between the object being constructed and the overload
|
||||||
|
/// candidate.
|
||||||
|
ovl_fail_object_addrspace_mismatch
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A list of implicit conversion sequences for the arguments of an
|
/// A list of implicit conversion sequences for the arguments of an
|
||||||
|
@ -878,6 +883,9 @@ class Sema;
|
||||||
unsigned NumInlineBytesUsed = 0;
|
unsigned NumInlineBytesUsed = 0;
|
||||||
llvm::AlignedCharArray<alignof(void *), NumInlineBytes> InlineSpace;
|
llvm::AlignedCharArray<alignof(void *), NumInlineBytes> InlineSpace;
|
||||||
|
|
||||||
|
// Address space of the object being constructed.
|
||||||
|
LangAS DestAS = LangAS::Default;
|
||||||
|
|
||||||
/// If we have space, allocates from inline storage. Otherwise, allocates
|
/// If we have space, allocates from inline storage. Otherwise, allocates
|
||||||
/// from the slab allocator.
|
/// from the slab allocator.
|
||||||
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
|
/// FIXME: It would probably be nice to have a SmallBumpPtrAllocator
|
||||||
|
@ -983,6 +991,17 @@ class Sema;
|
||||||
ArrayRef<OverloadCandidate *> Cands,
|
ArrayRef<OverloadCandidate *> Cands,
|
||||||
StringRef Opc = "",
|
StringRef Opc = "",
|
||||||
SourceLocation OpLoc = SourceLocation());
|
SourceLocation OpLoc = SourceLocation());
|
||||||
|
|
||||||
|
LangAS getDestAS() { return DestAS; }
|
||||||
|
|
||||||
|
void setDestAS(LangAS AS) {
|
||||||
|
assert((Kind == CSK_InitByConstructor ||
|
||||||
|
Kind == CSK_InitByUserDefinedConversion) &&
|
||||||
|
"can't set the destination address space when not constructing an "
|
||||||
|
"object");
|
||||||
|
DestAS = AS;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isBetterOverloadCandidate(Sema &S,
|
bool isBetterOverloadCandidate(Sema &S,
|
||||||
|
|
|
@ -8232,12 +8232,19 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R,
|
||||||
|
|
||||||
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
|
DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
|
||||||
if (FTI.hasMethodTypeQualifiers()) {
|
if (FTI.hasMethodTypeQualifiers()) {
|
||||||
|
bool DiagOccured = false;
|
||||||
FTI.MethodQualifiers->forEachQualifier(
|
FTI.MethodQualifiers->forEachQualifier(
|
||||||
[&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) {
|
[&](DeclSpec::TQ TypeQual, StringRef QualName, SourceLocation SL) {
|
||||||
|
// This diagnostic should be emitted on any qualifier except an addr
|
||||||
|
// space qualifier. However, forEachQualifier currently doesn't visit
|
||||||
|
// addr space qualifiers, so there's no way to write this condition
|
||||||
|
// right now; we just diagnose on everything.
|
||||||
Diag(SL, diag::err_invalid_qualified_constructor)
|
Diag(SL, diag::err_invalid_qualified_constructor)
|
||||||
<< QualName << SourceRange(SL);
|
<< QualName << SourceRange(SL);
|
||||||
|
DiagOccured = true;
|
||||||
});
|
});
|
||||||
D.setInvalidType();
|
if (DiagOccured)
|
||||||
|
D.setInvalidType();
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++0x [class.ctor]p4:
|
// C++0x [class.ctor]p4:
|
||||||
|
|
|
@ -3733,6 +3733,7 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
||||||
bool OnlyListConstructors, bool IsListInit,
|
bool OnlyListConstructors, bool IsListInit,
|
||||||
bool SecondStepOfCopyInit = false) {
|
bool SecondStepOfCopyInit = false) {
|
||||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
|
CandidateSet.clear(OverloadCandidateSet::CSK_InitByConstructor);
|
||||||
|
CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
|
||||||
|
|
||||||
for (NamedDecl *D : Ctors) {
|
for (NamedDecl *D : Ctors) {
|
||||||
auto Info = getConstructorInfo(D);
|
auto Info = getConstructorInfo(D);
|
||||||
|
@ -4985,6 +4986,7 @@ static void TryUserDefinedConversion(Sema &S,
|
||||||
// structure, so that it will persist if we fail.
|
// structure, so that it will persist if we fail.
|
||||||
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet();
|
||||||
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion);
|
||||||
|
CandidateSet.setDestAS(DestType.getQualifiers().getAddressSpace());
|
||||||
|
|
||||||
// Determine whether we are allowed to call explicit constructors or
|
// Determine whether we are allowed to call explicit constructors or
|
||||||
// explicit conversion operators.
|
// explicit conversion operators.
|
||||||
|
|
|
@ -6101,6 +6101,15 @@ void Sema::AddOverloadCandidate(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the constructor is capable of constructing an object in the
|
||||||
|
// destination address space.
|
||||||
|
if (!Qualifiers::isAddressSpaceSupersetOf(
|
||||||
|
Constructor->getMethodQualifiers().getAddressSpace(),
|
||||||
|
CandidateSet.getDestAS())) {
|
||||||
|
Candidate.Viable = false;
|
||||||
|
Candidate.FailureKind = ovl_fail_object_addrspace_mismatch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned NumParams = Proto->getNumParams();
|
unsigned NumParams = Proto->getNumParams();
|
||||||
|
@ -10392,9 +10401,12 @@ static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
|
||||||
/// It would be great to be able to express per-candidate problems
|
/// It would be great to be able to express per-candidate problems
|
||||||
/// more richly for those diagnostic clients that cared, but we'd
|
/// more richly for those diagnostic clients that cared, but we'd
|
||||||
/// still have to be just as careful with the default diagnostics.
|
/// still have to be just as careful with the default diagnostics.
|
||||||
|
/// \param CtorDestAS Addr space of object being constructed (for ctor
|
||||||
|
/// candidates only).
|
||||||
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
bool TakingCandidateAddress) {
|
bool TakingCandidateAddress,
|
||||||
|
LangAS CtorDestAS = LangAS::Default) {
|
||||||
FunctionDecl *Fn = Cand->Function;
|
FunctionDecl *Fn = Cand->Function;
|
||||||
|
|
||||||
// Note deleted candidates, but only if they're viable.
|
// Note deleted candidates, but only if they're viable.
|
||||||
|
@ -10432,6 +10444,16 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ovl_fail_object_addrspace_mismatch: {
|
||||||
|
Qualifiers QualsForPrinting;
|
||||||
|
QualsForPrinting.setAddressSpace(CtorDestAS);
|
||||||
|
S.Diag(Fn->getLocation(),
|
||||||
|
diag::note_ovl_candidate_illegal_constructor_adrspace_mismatch)
|
||||||
|
<< QualsForPrinting;
|
||||||
|
MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
case ovl_fail_trivial_conversion:
|
case ovl_fail_trivial_conversion:
|
||||||
case ovl_fail_bad_final_conversion:
|
case ovl_fail_bad_final_conversion:
|
||||||
case ovl_fail_final_conversion_not_exact:
|
case ovl_fail_final_conversion_not_exact:
|
||||||
|
@ -10862,7 +10884,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args,
|
||||||
|
|
||||||
if (Cand->Function)
|
if (Cand->Function)
|
||||||
NoteFunctionCandidate(S, Cand, Args.size(),
|
NoteFunctionCandidate(S, Cand, Args.size(),
|
||||||
/*TakingCandidateAddress=*/false);
|
/*TakingCandidateAddress=*/false, DestAS);
|
||||||
else if (Cand->IsSurrogate)
|
else if (Cand->IsSurrogate)
|
||||||
NoteSurrogateCandidate(S, Cand);
|
NoteSurrogateCandidate(S, Cand);
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
// RUN: %clang_cc1 %s -std=c++14 -triple=spir -emit-llvm -o - | FileCheck %s
|
// RUN: %clang_cc1 %s -std=c++14 -triple=spir -emit-llvm -o - | FileCheck %s
|
||||||
// RUN: %clang_cc1 %s -std=c++17 -triple=spir -emit-llvm -o - | FileCheck %s
|
// RUN: %clang_cc1 %s -std=c++17 -triple=spir -emit-llvm -o - | FileCheck %s
|
||||||
|
// XFAIL: *
|
||||||
|
|
||||||
|
// FIXME: We can't compile address space method qualifiers yet.
|
||||||
|
// Therefore there is no way to check correctness of this code.
|
||||||
struct MyType {
|
struct MyType {
|
||||||
MyType(int i) : i(i) {}
|
MyType(int i) __attribute__((address_space(10))) : i(i) {}
|
||||||
int i;
|
int i;
|
||||||
};
|
};
|
||||||
//CHECK: call void @_ZN6MyTypeC1Ei(%struct.MyType* addrspacecast (%struct.MyType addrspace(10)* @m to %struct.MyType*), i32 123)
|
//CHECK: call void @_ZN6MyTypeC1Ei(%struct.MyType* addrspacecast (%struct.MyType addrspace(10)* @m to %struct.MyType*), i32 123)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
// RUN: %clang_cc1 %s -triple spir-unknown-unknown -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
MyType(int i) : i(i) {}
|
||||||
|
MyType(int i) __constant : i(i) {}
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
//CHECK: call void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const1, i32 1)
|
||||||
|
__constant MyType const1 = 1;
|
||||||
|
//CHECK: call void @_ZNU3AS26MyTypeC1Ei(%struct.MyType addrspace(2)* @const2, i32 2)
|
||||||
|
__constant MyType const2(2);
|
||||||
|
//CHECK: call void @_ZNU3AS46MyTypeC1Ei(%struct.MyType addrspace(4)* addrspacecast (%struct.MyType addrspace(1)* @glob to %struct.MyType addrspace(4)*), i32 1)
|
||||||
|
MyType glob(1);
|
|
@ -0,0 +1,18 @@
|
||||||
|
// RUN: %clang_cc1 %s -std=c++14 -triple=spir -verify -fsyntax-only
|
||||||
|
// RUN: %clang_cc1 %s -std=c++17 -triple=spir -verify -fsyntax-only
|
||||||
|
|
||||||
|
struct MyType {
|
||||||
|
MyType(int i) : i(i) {}
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
|
||||||
|
//expected-note@-5{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const MyType &' for 1st argument}}
|
||||||
|
//expected-note@-6{{candidate constructor (the implicit move constructor) not viable: no known conversion from 'int' to 'MyType &&' for 1st argument}}
|
||||||
|
//expected-note@-6{{candidate constructor ignored: cannot be used to construct an object in address space '__attribute__((address_space(10)))'}}
|
||||||
|
//expected-note@-8{{candidate constructor ignored: cannot be used to construct an object in address space '__attribute__((address_space(10)))'}}
|
||||||
|
//expected-note@-9{{candidate constructor ignored: cannot be used to construct an object in address space '__attribute__((address_space(10)))'}}
|
||||||
|
//expected-note@-9{{candidate constructor ignored: cannot be used to construct an object in address space '__attribute__((address_space(10)))'}}
|
||||||
|
|
||||||
|
// FIXME: We can't implicitly convert between address spaces yet.
|
||||||
|
MyType __attribute__((address_space(10))) m1 = 123; //expected-error{{no viable conversion from 'int' to '__attribute__((address_space(10))) MyType'}}
|
||||||
|
MyType __attribute__((address_space(10))) m2(123); //expected-error{{no matching constructor for initialization of '__attribute__((address_space(10))) MyType'}}
|
Loading…
Reference in New Issue