Vedant Kumar a14a1f923f [Parse] Forward brace locations to TypeConstructExpr
When parsing C++ type construction expressions with list initialization,
forward the locations of the braces to Sema.

Without these locations, the code coverage pass crashes on the given test
case, because the pass relies on getLocEnd() returning a valid location.

Here is what this patch does in more detail:

  - Forwards init-list brace locations to Sema (ParseExprCXX),
  - Builds an InitializationKind with these locations (SemaExprCXX), and
  - Uses these locations for constructor initialization (SemaInit).

The remaining changes fall out of introducing a new overload for
creating direct-list InitializationKinds.

Testing: check-clang, and a stage2 coverage-enabled build of clang with
asserts enabled.

Differential Revision: https://reviews.llvm.org/D41921

llvm-svn: 322729
2018-01-17 18:53:51 +00:00

96 lines
3.1 KiB
C++

// RUN: %clang_cc1 -triple %itanium_abi_triple -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name classtemplate.cpp %s > %tmapping
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-CONSTRUCTOR
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-GETTER
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-SETTER
// RUN: FileCheck -input-file %tmapping %s --check-prefix=CHECK-INIT-LIST
template<class TT>
class Test {
public:
enum BaseType {
A, C, G, T, Invalid
};
const static int BaseCount = 4;
double bases[BaseCount];
// CHECK-CONSTRUCTOR: _ZN4TestIjEC
Test() { } // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:10 -> [[@LINE]]:13 = #0
// FIXME: It would be nice to emit no-coverage for get, but trying to do this
// runs afoul of cases like Test3::unmangleable below.
// FIXME-GETTER: _ZNK4TestIjE3get
double get(TT position) const { // FIXME-GETTER: File 0, [[@LINE]]:33 -> [[@LINE+2]]:4 = 0
return bases[position];
}
// CHECK-SETTER: _ZN4TestIjE3set
void set(TT position, double value) { // CHECK-SETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = #0
bases[position] = value;
}
};
class Test2 {
// CHECK-CONSTRUCTOR: _ZN5Test2C
Test2() { } // CHECK-CONSTRUCTOR: File 0, [[@LINE]]:11 -> [[@LINE]]:14 = 0
// CHECK-GETTER: _ZNK5Test23get
double get(unsigned position) const { // CHECK-GETTER: File 0, [[@LINE]]:39 -> [[@LINE+2]]:4 = 0
return 0.0;
}
};
// Test3::unmangleable can't be mangled, since there isn't a complete type for
// the __is_final type trait expression. This would cause errors if we try to
// emit a no-coverage mapping for the method.
template <class T, bool = __is_final(T)> class UninstantiatedClassWithTraits {};
template <class T> class Test3 {
void unmangleable(UninstantiatedClassWithTraits<T> x) {}
};
void abort() __attribute__((noreturn));
namespace std {
typedef decltype(sizeof(int)) size_t;
template <typename E> struct initializer_list {
const E *p;
size_t n;
initializer_list(const E *p, size_t n) : p(p), n(n) {}
};
template <typename F, typename S> struct pair {
F f;
S s;
pair(const F &f, const S &s) : f(f), s(s) {}
};
struct string {
const char *str;
string() { abort(); }
string(const char *S) : str(S) {}
~string() { abort(); }
};
template<typename K, typename V>
struct map {
using T = pair<K, V>;
map(initializer_list<T> i, const string &s = string()) {}
~map() { abort(); }
};
}; // namespace std
// CHECK-INIT-LIST-LABEL: _Z5Test4v:
std::map<int, int> Test4() { // CHECK-INIT-LIST: File 0, [[@LINE]]:28 -> [[@LINE+3]]:2 = #0
abort();
return std::map<int, int>{{0, 0}}; // CHECK-INIT-LIST-NEXT: [[@LINE]]:3 -> [[@LINE]]:36 = 0
}
int main() {
Test<unsigned> t;
t.set(Test<unsigned>::A, 5.5);
t.set(Test<unsigned>::T, 5.6);
t.set(Test<unsigned>::G, 5.7);
t.set(Test<unsigned>::C, 5.8);
Test4();
return 0;
}