From: David Majnemer Date: Sat, 10 Jan 2015 10:43:19 +0000 (+0000) Subject: Sema: The asm constraint '+&m' isn't valid, reject it X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a2cf25d8f4e3ad9d13346331832554066c25754e;p=clang Sema: The asm constraint '+&m' isn't valid, reject it Don't permit '+&m' to make it to CodeGen, it's invalid. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@225586 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index a2ff7e2541..69a5404468 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -531,6 +531,7 @@ public: CI_ReadWrite = 0x04, // "+r" output constraint (read and write). CI_HasMatchingInput = 0x08, // This output operand has a matching input. CI_ImmediateConstant = 0x10, // This operand must be an immediate constant + CI_EarlyClobber = 0x20, // "&" output constraint (early clobber). }; unsigned Flags; int TiedOperand; @@ -551,6 +552,7 @@ public: const std::string &getConstraintStr() const { return ConstraintStr; } const std::string &getName() const { return Name; } bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } + bool earlyClobber() { return (Flags & CI_EarlyClobber) != 0; } bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } @@ -576,6 +578,7 @@ public: int getImmConstantMax() const { return ImmRange.Max; } void setIsReadWrite() { Flags |= CI_ReadWrite; } + void setEarlyClobber() { Flags |= CI_EarlyClobber; } void setAllowsMemory() { Flags |= CI_AllowsMemory; } void setAllowsRegister() { Flags |= CI_AllowsRegister; } void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index f2dc84fa03..aabb70dd6b 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -459,7 +459,9 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { // Eventually, an unknown constraint should just be treated as 'g'. return false; } + break; case '&': // early clobber. + Info.setEarlyClobber(); break; case '%': // commutative. // FIXME: Check that there is a another register after this one. @@ -494,6 +496,11 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { Name++; } + // Early clobber with a read-write constraint which doesn't permit registers + // is invalid. + if (Info.earlyClobber() && Info.isReadWrite() && !Info.allowsRegister()) + return false; + // If a constraint allows neither memory nor register operands it contains // only modifiers. Reject it. return Info.allowsMemory() || Info.allowsRegister(); diff --git a/test/Sema/asm.c b/test/Sema/asm.c index e49888ff3e..2867acb1d3 100644 --- a/test/Sema/asm.c +++ b/test/Sema/asm.c @@ -171,3 +171,9 @@ void fn1() { : [l] "=r"(l) : "[l],m"(l)); // expected-error {{asm constraint has an unexpected number of alternatives: 1 vs 2}} } + +void fn2() { + int l; + __asm__("" + : "+&m"(l)); // expected-error {{invalid output constraint '+&m' in asm}} +}