Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -357,6 +357,10 @@ "static data member of %2|" "field of %2}1">, InGroup, DefaultIgnore; + +def error_inoutput_conflict_with_clobber : Error< + "asm-specifier for input or output variable conflicts with asm" + " clobber list">; // C++ using declarations def err_using_requires_qualname : Error< Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -164,6 +164,9 @@ return NS; } + std::vector > InputVars; + std::vector > OutputVars; + for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); @@ -201,6 +204,26 @@ if (OutputExpr->isTypeDependent()) continue; + // Add the output's register and location in the command line in order to + // check for conflicts with the clobber list + if (const DeclRefExpr *AsmDeclRef = dyn_cast(OutputExpr)){ + // Handle cases where the output expression is a variable + const VarDecl *Variable = dyn_cast(AsmDeclRef->getDecl()); + if (Variable && Variable->getStorageClass() == SC_Register){ + AsmLabelAttr *Attr = Variable->getAttr(); + if (Attr){ + OutputVars.push_back(std::pair( + // Mapping the actual register with the appropriate variable in the asm output variables list + Attr->getLabel(), OutputExpr->getSourceRange().getBegin())); + } + } + } else if (const StringLiteral *AsmStringLit = + dyn_cast(OutputExpr)) { + // Handle cases where the output expression is a explicit register + OutputVars.push_back(std::pair( + AsmStringLit->getString(), OutputExpr->getSourceRange().getBegin())); + } + Expr::isModifiableLvalueResult IsLV = OutputExpr->isModifiableLvalue(Context, /*Loc=*/nullptr); switch (IsLV) { @@ -304,6 +327,26 @@ Exprs[i] = Result.get(); } + // Add the input's register and location in the command line in order to + // check for conflicts with the clobber list + if (const DeclRefExpr *AsmDeclRef = dyn_cast(InputExpr)){ + // Handle cases where the input expression is a variable + const VarDecl *Variable = dyn_cast(AsmDeclRef->getDecl()); + if (Variable && Variable->getStorageClass() == SC_Register){ + AsmLabelAttr *Attr = Variable->getAttr(); + if (Attr){ + InputVars.push_back(std::pair( + // Mapping the actual register with the appropriate variable in the asm input variables list + Attr->getLabel(), InputExpr->getSourceRange().getBegin())); + } + } + } else if (const StringLiteral *AsmStringLit = + dyn_cast(InputExpr)) { + // Handle cases where the output expression is a explicit register + InputVars.push_back(std::pair( + AsmStringLit->getString(), InputExpr->getSourceRange().getBegin())); + } + if (Info.allowsRegister()) { if (InputExpr->getType()->isVoidType()) { return StmtError(Diag(InputExpr->getLocStart(), @@ -342,6 +385,18 @@ if (!Context.getTargetInfo().isValidClobber(Clobber)) return StmtError(Diag(Literal->getLocStart(), diag::err_asm_unknown_register_name) << Clobber); + // Check if same register appears in both output list and clobber list + for (auto it = OutputVars.begin(); it != OutputVars.end(); ++it) { + if (Clobber == it->first) + return StmtError( + Diag(it->second, diag::error_inoutput_conflict_with_clobber)); + } + // Check if same register appears in both input list and clobber list + for (auto it = InputVars.begin(); it != InputVars.end(); ++it) { + if (Clobber == it->first) + return StmtError( + Diag(it->second, diag::error_inoutput_conflict_with_clobber)); + } } GCCAsmStmt *NS = Index: test/Sema/asm.c =================================================================== --- test/Sema/asm.c +++ test/Sema/asm.c @@ -28,6 +28,17 @@ asm ("nop" : : : "104"); // expected-error {{unknown register name '104' in asm}} asm ("nop" : : : "-1"); // expected-error {{unknown register name '-1' in asm}} asm ("nop" : : : "+1"); // expected-error {{unknown register name '+1' in asm}} + register void *clobber_conflict asm ("%rcx"); + register void *no_clobber_conflict asm ("%rax"); + asm ("nop" : "=r" (no_clobber_conflict) : "r" (clobber_conflict) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" (clobber_conflict) : "r" (no_clobber_conflict) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" (clobber_conflict) : "r" (clobber_conflict) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" ("%rcx") : "r" (no_clobber_conflict) : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" (no_clobber_conflict) : "r" ("%rcx") : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" ("%rcx") : "r" ("%rcx") : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" (clobber_conflict) : "r" ("%rcx") : "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" ("%rcx") : "r" ("%rcx") : "%rbx", "%rcx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} + asm ("nop" : "=r" ("%rcx") : "r" ("%rax") : "%rcx", "%rbx"); // expected-error {{asm-specifier for input or output variable conflicts with asm clobber list}} } // rdar://6094010