129 lines
5.3 KiB
C++
129 lines
5.3 KiB
C++
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -triple x86_64-gnu-linux
|
|
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -triple x86_64-gnu-linux -fexperimental-new-constant-interpreter
|
|
|
|
template <bool Leak>
|
|
struct RAIIBase {
|
|
constexpr RAIIBase(const char* in) {
|
|
s = __builtin_strlen(in);
|
|
d = new char[s + 1]; // expected-note 4{{allocation performed here was not deallocated}}
|
|
for(int i = 0 ; i < s; i++)
|
|
d[i] = in[i];
|
|
}
|
|
int s;
|
|
char* d;
|
|
constexpr unsigned long size() const {
|
|
return s;
|
|
}
|
|
constexpr const char* data() const {
|
|
return d;
|
|
}
|
|
constexpr ~RAIIBase() {
|
|
if constexpr(!Leak)
|
|
delete[] d;
|
|
}
|
|
};
|
|
|
|
using RAII = RAIIBase<false>;
|
|
using RAIILeak = RAIIBase<true>;
|
|
|
|
void test_leaks(int i) {
|
|
asm((RAII("nop")) : (RAII("+ir")) (i) : (RAII("g")) (i) : (RAII("memory")));
|
|
asm((RAIILeak("nop"))); // expected-error {{the expression in this asm operand must be produced by a constant expression}}
|
|
asm((RAII("nop"))
|
|
: (RAIILeak("+ir")) (i) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
|
|
::
|
|
);
|
|
asm((RAII("nop"))
|
|
: (RAII("+ir")) (i)
|
|
: (RAIILeak("g")) (i) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
|
|
:
|
|
);
|
|
asm((RAII("nop"))
|
|
: (RAII("+ir")) (i)
|
|
: (RAII("g")) (i)
|
|
: (RAIILeak("memory")) // expected-error {{the expression in this asm operand must be produced by a constant expression}}
|
|
);
|
|
}
|
|
|
|
struct NotAString{};
|
|
struct MessageInvalidSize {
|
|
constexpr unsigned long size(int) const; // expected-note {{'size' declared here}}
|
|
constexpr const char* data() const;
|
|
};
|
|
struct MessageInvalidData {
|
|
constexpr unsigned long size() const;
|
|
constexpr const char* data(int) const; // expected-note {{'data' declared here}}
|
|
};
|
|
|
|
|
|
struct WMessage {
|
|
constexpr unsigned long long size() const {return 0;};
|
|
constexpr const wchar_t* data() const {return L"";}
|
|
};
|
|
|
|
struct string_view {
|
|
int S;
|
|
const char* D;
|
|
constexpr string_view() : S(0), D(0){}
|
|
constexpr string_view(const char* Str) : S(__builtin_strlen(Str)), D(Str) {}
|
|
constexpr string_view(int Size, const char* Str) : S(Size), D(Str) {}
|
|
constexpr int size() const {
|
|
return S;
|
|
}
|
|
constexpr const char* data() const {
|
|
return D;
|
|
}
|
|
};
|
|
|
|
|
|
void f() {
|
|
asm(("")); // expected-error {{the expression in this asm operand must be a string literal or an object with 'data()' and 'size()' member functions}}
|
|
asm((NotAString{})); // expected-error {{the string object in this asm operand is missing 'data()' and 'size()' member functions}}
|
|
asm((MessageInvalidData{})); // expected-error {{the expression in this asm operand must have a 'data()' member function returning an object convertible to 'const char *'}} \
|
|
// expected-error {{too few arguments to function call, expected 1, have 0}}
|
|
asm((MessageInvalidSize{})); // expected-error {{the expression in this asm operand must have a 'size()' member function returning an object convertible to 'std::size_t'}} \
|
|
// expected-error {{too few arguments to function call, expected 1, have 0}}
|
|
|
|
asm((WMessage{})); // expected-error {{value of type 'const wchar_t *' is not implicitly convertible to 'const char *'}} \
|
|
// expected-error {{the expression in this asm operand must have a 'data()' member function returning an object convertible to 'const char *'}}
|
|
}
|
|
|
|
template <typename... U>
|
|
void test_packs() {
|
|
asm((U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
|
|
asm("" : (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
|
|
asm("" :: (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
|
|
asm("" ::: (U{})); // expected-error {{expression contains unexpanded parameter pack 'U'}}
|
|
}
|
|
|
|
template <typename T>
|
|
void test_dependent1(int i) {
|
|
asm((T{})); // #err-int
|
|
asm("" : (T{"+g"})(i)); // #err-int2
|
|
asm("" :: (T{"g"})(i)); // #err-int3
|
|
asm("" ::: (T{"memory"})); // #err-int4
|
|
}
|
|
|
|
template void test_dependent1<int>(int);
|
|
// expected-note@-1 {{in instantiation of function template specialization}}
|
|
// expected-error@#err-int {{the expression in this asm operand must be a string literal or an object with 'data()' and 'size()' member functions}}
|
|
// expected-error@#err-int2 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[3]'}}
|
|
// expected-error@#err-int3 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[2]'}}
|
|
// expected-error@#err-int4 {{cannot initialize a value of type 'int' with an lvalue of type 'const char[7]'}}
|
|
|
|
template void test_dependent1<string_view>(int);
|
|
|
|
|
|
template <typename T>
|
|
void test_dependent2(int i) {
|
|
asm("" : (T{"g"})(i)); // #err-invalid1
|
|
asm("" :: (T{"+g"})(i)); // #err-invalid2
|
|
asm("" ::: (T{"foo"})); // #err-invalid3
|
|
}
|
|
template void test_dependent2<string_view>(int);
|
|
// expected-note@-1 {{in instantiation of function template specialization}}
|
|
// expected-error@#err-invalid1 {{invalid output constraint 'g' in asm}}
|
|
// expected-error@#err-invalid2 {{invalid input constraint '+g' in asm}}
|
|
// expected-error@#err-invalid3 {{unknown register name 'foo' in asm}}
|
|
|