You can also get a good idea of what the compiler will do by making use of your compiler's assembler or something like this online utility: https://godbolt.org and taking a look at the resulting assembly code.
This was worth a look, since the question is fundamental.
An example based on your question, looking at primitives vs "complex" (not even very) considering local vs static type declaration and instantiation:
#include <iostream>
struct non_primitive
{
int v;
non_primitive(const int v_) : v(v_) {}
};
void test_non_static_const_primitive()
{
const int ABC = 12;
std::cout << ABC;
}
void test_static_const_primitive()
{
const static int ABC = 12;
std::cout << ABC;
}
void test_non_static_constant_non_primitive_global_struct()
{
const non_primitive s(12);
std::cout << s.v;
}
void test_non_static_constant_non_primitive_local_struct()
{
struct local_non_primitive
{
int v;
local_non_primitive(const int v_) : v(v_) {}
};
const local_non_primitive s(12);
std::cout << s.v;
}
void test_static_constant_non_primitive_global_struct()
{
const static non_primitive s(12);
std::cout << s.v;
}
void test_static_constant_non_primitive_local_struct()
{
struct local_non_primitive
{
int v;
local_non_primitive(const int v_) : v(v_) {}
};
const static local_non_primitive s(12);
std::cout << s.v;
}
The compiler recognizes that it doesn't have to deal with any memory linkage for local const complex types, and the first four cases are treated identically. It looks like the compiler doesn't try to explore the complex type's relative simplicity and potential for further simplification in the static instantiation.
The resulting cost difference is relatively huge.
The compiled assembly code using gcc7.2 with -O3 optimization:
test_non_static_const_primitive():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_const_primitive():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_non_static_constant_non_primitive_global_struct():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_non_static_constant_non_primitive_local_struct():
mov esi, 12
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_constant_non_primitive_global_struct():
movzx eax, BYTE PTR guard variable for test_static_constant_non_primitive_global_struct()::s[rip]
test al, al
je .L7
mov esi, DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip]
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
.L7:
sub rsp, 8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_global_struct()::s
call __cxa_guard_acquire
test eax, eax
mov esi, DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip]
je .L8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_global_struct()::s
mov DWORD PTR test_static_constant_non_primitive_global_struct()::s[rip], 12
call __cxa_guard_release
mov esi, 12
.L8:
mov edi, OFFSET FLAT:std::cout
add rsp, 8
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
test_static_constant_non_primitive_local_struct():
movzx eax, BYTE PTR guard variable for test_static_constant_non_primitive_local_struct()::s[rip]
test al, al
je .L14
mov esi, DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip]
mov edi, OFFSET FLAT:std::cout
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
.L14:
sub rsp, 8
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_local_struct()::s
call __cxa_guard_acquire
test eax, eax
mov esi, DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip]
je .L15
mov edi, OFFSET FLAT:guard variable for test_static_constant_non_primitive_local_struct()::s
mov DWORD PTR test_static_constant_non_primitive_local_struct()::s[rip], 12
call __cxa_guard_release
mov esi, 12
.L15:
mov edi, OFFSET FLAT:std::cout
add rsp, 8
jmp std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
_GLOBAL__sub_I__Z31test_non_static_const_primitivev:
sub rsp, 8
mov edi, OFFSET FLAT:std::__ioinit
call std::ios_base::Init::Init()
mov edx, OFFSET FLAT:__dso_handle
mov esi, OFFSET FLAT:std::__ioinit
mov edi, OFFSET FLAT:std::ios_base::Init::~Init()
add rsp, 8
jmp __cxa_atexit