/* mbed Microcontroller Library
 * Copyright (c) 2006-2013 ARM Limited
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef MBED_TOOLCHAIN_H
#define MBED_TOOLCHAIN_H


// Warning for unsupported compilers
#if !defined(__GNUC__)   /* GCC        */ \
 && !defined(__CC_ARM)   /* ARMCC      */ \
 && !defined(__clang__)  /* LLVM/Clang */ \
 && !defined(__ICCARM__) /* IAR        */
#warning "This compiler is not yet supported."
#endif


// Attributes

/** MBED_PACKED
 *  Pack a structure, preventing any padding from being added between fields.
 *
 *  @code
 *  #include "toolchain.h"
 *
 *  MBED_PACKED(struct) foo {
 *      char x;
 *      int y;
 *  };
 *  @endcode
 */
#ifndef MBED_PACKED
#if defined(__ICCARM__)
#define MBED_PACKED(struct) __packed struct
#else
#define MBED_PACKED(struct) struct __attribute__((packed))
#endif
#endif

/** MBED_ALIGN(N)
 *  Declare a variable to be aligned on an N-byte boundary.
 *
 *  @note
 *  IAR does not support alignment greater than word size on the stack
 *  
 *  @code
 *  #include "toolchain.h"
 *
 *  MBED_ALIGN(16) char a;
 *  @endcode
 */
#ifndef MBED_ALIGN
#if defined(__ICCARM__)
#define _MBED_ALIGN(N) _Pragma(#N)
#define MBED_ALIGN(N) _MBED_ALIGN(data_alignment=N)
#else
#define MBED_ALIGN(N) __attribute__((aligned(N)))
#endif
#endif

/** MBED_UNUSED
 *  Declare a function argument to be unused, suppressing compiler warnings
 *
 *  @code
 *  #include "toolchain.h"
 *
 *  void foo(MBED_UNUSED int arg) {
 *
 *  }
 *  @endcode
 */
#ifndef MBED_UNUSED
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
#define MBED_UNUSED __attribute__((__unused__))
#else
#define MBED_UNUSED
#endif
#endif

/** MBED_WEAK
 *  Mark a function as being weak.
 *  
 *  @note
 *  weak functions are not friendly to making code re-usable, as they can only
 *  be overridden once (and if they are multiply overridden the linker will emit
 *  no warning). You should not normally use weak symbols as part of the API to
 *  re-usable modules.
 *  
 *  @code
 *  #include "toolchain.h"
 *  
 *  MBED_WEAK void foo() {
 *      // a weak implementation of foo that can be overriden by a definition
 *      // without  __weak
 *  }
 *  @endcode
 */
#ifndef MBED_WEAK
#if defined(__ICCARM__)
#define MBED_WEAK __weak
#else
#define MBED_WEAK __attribute__((weak))
#endif
#endif

/** MBED_PURE
 *  Hint to the compiler that a function depends only on parameters
 *
 *  @code
 *  #include "toolchain.h"
 *
 *  MBED_PURE int foo(int arg){
 *      // no access to global variables
 *  }
 *  @endcode
 */
#ifndef MBED_PURE
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
#define MBED_PURE __attribute__((const))
#else
#define MBED_PURE
#endif
#endif

/** MBED_FORCEINLINE
 *  Declare a function that must always be inlined. Failure to inline
 *  such a function will result in an error.
 *
 *  @code
 *  #include "toolchain.h"
 *  
 *  MBED_FORCEINLINE void foo() {
 *  
 *  }
 *  @endcode
 */
#ifndef MBED_FORCEINLINE
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
#define MBED_FORCEINLINE static inline __attribute__((always_inline))
#elif defined(__ICCARM__)
#define MBED_FORCEINLINE _Pragma("inline=forced") static
#else
#define MBED_FORCEINLINE static inline
#endif
#endif

/** MBED_NORETURN
 *  Declare a function that will never return.
 *
 *  @code
 *  #include "toolchain.h"
 *  
 *  MBED_NORETURN void foo() {
 *      // must never return
 *      while (1) {}
 *  }
 *  @endcode
 */
#ifndef MBED_NORETURN
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
#define MBED_NORETURN __attribute__((noreturn))
#elif defined(__ICCARM__)
#define MBED_NORETURN __noreturn
#else
#define MBED_NORETURN
#endif
#endif

/** MBED_UNREACHABLE
 *  An unreachable statement. If the statement is reached,
 *  behaviour is undefined. Useful in situations where the compiler
 *  cannot deduce the unreachability of code.
 *
 *  @code
 *  #include "toolchain.h"
 *
 *  void foo(int arg) {
 *      switch (arg) {
 *          case 1: return 1;
 *          case 2: return 2;
 *          ...
 *      }
 *      MBED_UNREACHABLE;
 *  }
 *  @endcode
 */
#ifndef MBED_UNREACHABLE
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__CC_ARM)
#define MBED_UNREACHABLE __builtin_unreachable()
#else
#define MBED_UNREACHABLE while (1)
#endif
#endif

/** MBED_DEPRECATED("message string")
 *  Mark a function declaration as deprecated, if it used then a warning will be
 *  issued by the compiler possibly including the provided message. Note that not
 *  all compilers are able to display the message.
 *
 *  @code
 *  #include "toolchain.h"
 *  
 *  MBED_DEPRECATED("don't foo any more, bar instead")
 *  void foo(int arg);
 *  @endcode
 */
#ifndef MBED_DEPRECATED
#if defined(__GNUC__) || defined(__clang__)
#define MBED_DEPRECATED(M) __attribute__((deprecated(M)))
#elif defined(__CC_ARM)
#define MBED_DEPRECATED(M) __attribute__((deprecated))
#else
#define MBED_DEPRECATED(M)
#endif
#endif

/** MBED_DEPRECATED_SINCE("version", "message string")
 *  Mark a function declaration as deprecated, noting that the declaration was
 *  deprecated on the specified version. If the function is used then a warning
 *  will be issued by the compiler possibly including the provided message.
 *  Note that not all compilers are able to display this message.
 *
 *  @code
 *  #include "toolchain.h"
 *
 *  MBED_DEPRECATED_SINCE("mbed-os-5.1", "don't foo any more, bar instead")
 *  void foo(int arg);
 *  @endcode
 */
#define MBED_DEPRECATED_SINCE(D, M) MBED_DEPRECATED(M " [since " D "]")

/** MBED_CALLER_ADDR()
 * Returns the caller of the current function.
 *
 * @note
 * This macro is only implemented for GCC and ARMCC.
 *
 * @code
 * #include "toolchain.h"
 *
 * printf("This function was called from %p", MBED_CALLER_ADDR());
 * @endcode
 *
 * @return Address of the calling function
 */
#ifndef MBED_CALLER_ADDR
#if (defined(__GNUC__) || defined(__clang__)) && !defined(__CC_ARM)
#define MBED_CALLER_ADDR() __builtin_extract_return_addr(__builtin_return_address(0))
#elif defined(__CC_ARM)
#define MBED_CALLER_ADDR() __builtin_return_address(0)
#else
#define MBED_CALLER_ADDR() (NULL)
#endif
#endif

// FILEHANDLE declaration
#if defined(TOOLCHAIN_ARM)
#include <rt_sys.h>
#endif

#ifndef FILEHANDLE
typedef int FILEHANDLE;
#endif

// Backwards compatibility
#ifndef WEAK
#define WEAK MBED_WEAK
#endif

#ifndef PACKED
#define PACKED MBED_PACKED()
#endif

#ifndef EXTERN
#define EXTERN extern
#endif

#endif
