// RUN: %clang_analyze_cc1 \
// RUN:  -analyzer-checker=core.CallAndMessage \
// RUN:  -analyzer-config suppress-null-return-paths=false \
// RUN:  -verify %s
// RUN: %clang_analyze_cc1 \
// RUN:  -analyzer-checker=core.CallAndMessage \
// RUN:  -DSUPPRESSED \
// RUN:  -verify %s

#ifdef SUPPRESSED
// expected-no-diagnostics
#endif

#include <stdint.h>
#include "../Inputs/system-header-simulator-cxx.h"

void error();
void *malloc(size_t);


// From llvm/include/llvm/Support/MathExtras.h
inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
  return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
}

inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
  return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
}


// From llvm/include/llvm/Support/MemAlloc.h
inline void *safe_malloc(size_t Sz) {
  void *Result = malloc(Sz);
  if (Result == nullptr)
    error();

  return Result;
}


// From llvm/include/llvm/Support/Allocator.h
class MallocAllocator {
public:
  void *Allocate(size_t Size, size_t /*Alignment*/) {
    return safe_malloc(Size);
  }
};

class BumpPtrAllocator {
public:
  void *Allocate(size_t Size, size_t Alignment) {
    BytesAllocated += Size;
    size_t Adjustment = alignmentAdjustment(CurPtr, Alignment);
    size_t SizeToAllocate = Size;

    size_t PaddedSize = SizeToAllocate + Alignment - 1;
    uintptr_t AlignedAddr = alignAddr(Allocator.Allocate(PaddedSize, 0),
                                      Alignment);
    char *AlignedPtr = (char*)AlignedAddr;

    return AlignedPtr;
  }

private:
  char *CurPtr = nullptr;
  size_t BytesAllocated = 0;
  MallocAllocator Allocator;
};


// From clang/include/clang/AST/ASTContextAllocate.h
class ASTContext;

void *operator new(size_t Bytes, const ASTContext &C, size_t Alignment = 8);
void *operator new[](size_t Bytes, const ASTContext &C, size_t Alignment = 8);


// From clang/include/clang/AST/ASTContext.h
class ASTContext {
public:
  void *Allocate(size_t Size, unsigned Align = 8) const {
    return BumpAlloc.Allocate(Size, Align);
  }

  template <typename T>
  T *Allocate(size_t Num = 1) const {
    return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
  }

private:
  mutable BumpPtrAllocator BumpAlloc;
};


// From clang/include/clang/AST/ASTContext.h
inline void *operator new(size_t Bytes, const ASTContext &C,
                          size_t Alignment /* = 8 */) {
  return C.Allocate(Bytes, Alignment);
}

inline void *operator new[](size_t Bytes, const ASTContext &C,
                            size_t Alignment /* = 8 */) {
  return C.Allocate(Bytes, Alignment);
}


// From clang/include/clang/AST/Attr.h
void *operator new(size_t Bytes, ASTContext &C,
                   size_t Alignment = 8) noexcept {
  return ::operator new(Bytes, C, Alignment);
}


class A {
public:
  void setValue(int value) { Value = value; }
private:
  int Value;
};

void f(const ASTContext &C) {
  A *a = new (C) A;
  a->setValue(13);
#ifndef SUPPRESSED
  // expected-warning@-2 {{Called C++ object pointer is null}}
#endif
}	

void g(const ASTContext &C) {
  A *a = new (C) A[1];
  a[0].setValue(13);
#ifndef SUPPRESSED
  // expected-warning@-2 {{Called C++ object pointer is null}}
#endif
}

