Я пытался изменить некоторый синтаксис, чтобы заставить пользователя включить периферийные часы перед доступом в простой библиотеке для процессора STM32F4 Cortex-M4, которую я написал.
После нескольких часов работы с кодом, который не работал, я не смог найти, что я делаю неправильно, и попытался скомпилировать его с помощью Linux G ++, но это удалось.
Это ошибка компилятора в ARM g ++, или я использовал нестандартное поведение, которое Linux g ++ разрешал мне раньше?
Вот упрощенный пример кода:
#include <cstdint>
template<std::size_t port>
class Port
{
public: //Declarations
enum class PinMode
{
Input = 0x0,
Output = 0x1,
Alternate = 0x2,
Analog = 0x3
};
template<uint8_t nPin, PinMode mode>
class Pin
{
};
template<uint8_t nPin>
class Pin<nPin, PinMode::Output>
{
public: //Declarations
enum class OutputSpeed : uint32_t
{
Low,
Medium,
Fast,
High
};
enum class PullMode : uint32_t
{
None = 0x0,
PullUp = 0x1,
PullDown = 0x2
};
public: //Methods
void setOutputSpeed(OutputSpeed const ospeed) volatile;
void setPullMode(PullMode const ppm) volatile;
void set() volatile
{
reinterpret_cast<Port<port> volatile*>(port)->m_BSRR |= static_cast<uint16_t>(0x1) <<nPin;
}
void reset() volatile;
bool getOutputState() volatile;
}; //END OutputPin
public: //Registers
uint32_t m_BSRR;
}; //END Port
int main()
{
auto pin = Port<0>::Pin<5, Port<0>::PinMode::Output>();
pin.set();
}
ARM g ++ выход.
Using built-in specs.
COLLECT_GCC=arm-none-eabi-g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-none-eabi/4.8.2/lto-wrapper
Target: arm-none-eabi
Configured with: ../configure --target=arm-none-eabi --prefix=/usr --libexecdir=/usr/lib --with-pkgversion='Arch Repository' --with-bugurl=https://bugs.archlinux.org/ --enable-multilib --enable-interwork --enable-languages=c,c++ --with-newlib --with-gnu-as --with-gnu-ld --disable-nls --disable-shared --disable-threads --with-headers=newlib/libc/include --disable-libssp --disable-libstdcxx-pch --disable-libmudflap --disable-libgomp --with-system-zlib --disable-newlib-supplied-syscalls
Thread model: single
gcc version 4.8.2 (Arch Repository)
COLLECT_GCC_OPTIONS='-std=c++11' '-v'
/usr/lib/gcc/arm-none-eabi/4.8.2/cc1plus -quiet -v -D__USES_INITFINI__ test.cpp -quiet -dumpbase test.cpp -auxbase test -std=c++11 -version -o /tmp/cc6TlpeV.s
GNU C++ (Arch Repository) version 4.8.2 (arm-none-eabi)
compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/sys-include"#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2/arm-none-eabi
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include/c++/4.8.2/backward
/usr/lib/gcc/arm-none-eabi/4.8.2/include
/usr/lib/gcc/arm-none-eabi/4.8.2/include-fixed
/usr/lib/gcc/arm-none-eabi/4.8.2/../../../../arm-none-eabi/include
End of search list.
GNU C++ (Arch Repository) version 4.8.2 (arm-none-eabi)
compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 8ead046d6b54a8fe43e9a23d5562e5d4
test.cpp: In function 'int main()':
test.cpp:60:7: error: 'class Port<0u>::Pin<5u, (Port<0u>::PinMode)1>' has no member named 'set'
pin.set();
^
Вывод G ++:
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /build/gcc/src/gcc-4.8-20140206/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-cloog-backend=isl --disable-cloog-version-check --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --disable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 4.8.2 20140206 (prerelease) (GCC)
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/cc1plus -quiet -v -D_GNU_SOURCE test.cpp -quiet -dumpbase test.cpp -mtune=generic -march=x86-64 -auxbase test -std=c++11 -version -o /tmp/ccgCeLLA.s
GNU C++ (GCC) version 4.8.2 20140206 (prerelease) (x86_64-unknown-linux-gnu)
compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../x86_64-unknown-linux-gnu/include"#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/x86_64-unknown-linux-gnu
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/backward
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/include
/usr/local/include
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/include-fixed
/usr/include
End of search list.
GNU C++ (GCC) version 4.8.2 20140206 (prerelease) (x86_64-unknown-linux-gnu)
compiled by GNU C version 4.8.2 20140206 (prerelease), GMP version 5.1.3, MPFR version 3.1.2-p5, MPC version 1.0.2
warning: GMP header version 5.1.3 differs from library version 6.0.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 51ac5eb9b6c30af2da1950e6dfed6398
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccWIQqrr.o /tmp/ccgCeLLA.s
GNU assembler version 2.24 (x86_64-unknown-linux-gnu) using BFD version (GNU Binutils) 2.24
COMPILER_PATH=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-std=c++11' '-v' '-shared-libgcc' '-mtune=generic' '-march=x86-64'
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/collect2 --build-id --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crti.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtbegin.o -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2 -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../.. /tmp/ccWIQqrr.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/crtend.o /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crtn.o
Не совсем «ответ», но слишком много текста, чтобы написать в комментарии. Я вижу ту же проблему в моем g ++ 4.8.2 для x86-64 (самодельный из источника, примерно в конце или марте / начале апреля).
Казалось бы, компилятор выбирает ваш общий шаблон, а не специализированный.
template<uint8_t nPin, PinMode mode>
class Pin
{
};
который действительно не имеет set
член. Если я добавлю set
член в этом классе, код компилируется. Я не уверен, почему компилятор считает, что лучше использовать это, чем специализированный класс. Я подозреваю, что это ошибка в 4.8.2.
(Я заметил, что ваш g ++ 4.8.2 для x86-64 — это «предварительный выпуск», который может объяснить, почему он отличается в двух архитектурах).
Компилируется в clang ++ 3.5 (по состоянию на вчерашнюю нестабильную ветку) и g ++ 4.6.3. Он не компилируется с clang ++ 2.9.
В вашем коде есть две проблемы.
Не знаю почему, но наличие класса enum в шаблонах не работает должным образом. Поскольку это угловой шаблон и новая функция c ++, трудно найти точное место в стандарте, которое запрещает это. Это может быть даже ошибка компилятора.
Итак, исправленный код выглядит так:
#include <cstdint>
enum class PinMode
{
Input = 0x0,
Output = 0x1,
Alternate = 0x2,
Analog = 0x3
};
enum class OutputSpeed : uint32_t
{
Low,
Medium,
Fast,
High
};
enum class PullMode : uint32_t
{
None = 0x0,
PullUp = 0x1,
PullDown = 0x2
};
template<std::size_t port>
class Port
{
public: //Declarationstemplate<uint8_t nPin, PinMode mode>
class Pin;
template<uint8_t nPin>
class Pin<nPin, PinMode::Output>
{
public: //Methods
void setOutputSpeed(OutputSpeed const ospeed) volatile;
void setPullMode(PullMode const ppm) volatile;
void set() volatile
{
reinterpret_cast<Port<port> volatile*>(port)->m_BSRR |= static_cast<uint16_t>(0x1) <<nPin;
}
void reset() volatile;
bool getOutputState() volatile;
}; //END OutputPin
public: //Registers
uint32_t m_BSRR;
}; //END Port
int main()
{
auto pin = Port<0>::Pin< 5, PinMode::Output >();
pin.set();
}