First when you declare a variable as const, the compiler will never put it in ROM, because ... neither the compiler, nor the linker, nor later loader can write anything in ROM ! It can only put it in read-only segments that will still reside in RAM even if any write access at run time will cause an error.
Then to answer more precisely your question, the compiler may always do what it wants.
- when you declare a variable
const, the compiler should throw an error if it detects a change and can put it in a read-only segment
- when you declare a variable
register, the compiler should throw en error if it detects an attempt to take its address, and can try to keep it in register.
The only thing that is explicitely required is that a compiler correctly processes correct code. It is requested to throw an error if it cannot compile some code, but it is allowed to accept incorrect code : that may be called extensions or special features. For example a compiler is free to declare that it fully ignores register declaration and allows taking the address of a register variable but it must at least issue a warning [edit see below for details]. Simply it must not choke on correct register (or const usage).
And it can make use of register and const declaration for its optimisations but is perfectly free to ignore them. For example the following code :
const int a = 5;
const int *b = (int *) &a;
*b = 4;
leads to Undefined Behaviour. It is implementation dependant if after that :
- a = 5
- a = 4
- the program crashed
- the computer was burned to fire (but this one should be uncommon :-) )
- ...
EDIT :
JensGustedt noted in comment that C language specification contains in paragraph 6.5.3.2 Address and indirection operators this constraint clause :
The operand of the unary & operator shall ..., or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier. (emphasize mine)
As it in a constraint clause, paragraph 5.1.1.3 Diagnostics of same specification requires that A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint.
So a conforming C compiler shall at least issue a warning if programmer tries to take the address of a register variable.